Last active
September 19, 2017 15:45
-
-
Save fumiyasac/54778bee4fa6f75b29b331f770f9c02f to your computer and use it in GitHub Desktop.
NativeBaseをはじめとするUI関連のライブラリを活用してReactNativeでUIサンプルを作成した際の詳細解説 ref: http://qiita.com/fumiyasac@github/items/12707f93f5c96fa3fc3f
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* アプリコンテンツ用のコンポーネント | |
*/ | |
import React, { Component } from 'react'; | |
//react-native-router-fluxのインポート宣言(Actionを使用) | |
import { Router, Scene } from 'react-native-router-flux'; | |
//自作コンポーネント | |
import BaseContents from './components/BaseContents'; | |
import ShopDetailContents from './components/ShopDetailContents'; | |
import PhotoGalleryContents from './components/PhotoGalleryContents'; | |
//コンポーネントの内容を定義する ※ ClassComponent | |
class App extends Component { | |
//各種ルーティングに対応するコンポーネントの内容をレンダリングする | |
/** | |
* Memo: | |
* モーダルのような遷移をする場合は「direction="vertical"」を属性に設定する。 | |
*/ | |
render() { | |
return ( | |
<Router> | |
<Scene key="root"> | |
<Scene key="BaseContents" initial={true} component={BaseContents} hideNavBar={true} /> | |
<Scene key="ShopDetailContents" component={ShopDetailContents} hideNavBar={true} /> | |
<Scene key="PhotoGalleryContents" component={PhotoGalleryContents} hideNavBar={true} /> | |
</Scene> | |
</Router> | |
); | |
} | |
} | |
export default App; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ベースコンテンツ用のコンポーネント | |
*/ | |
/* ・・・(省略)・・・ */ | |
//NativeBaseを使用したコンポーネントの呼び出し | |
import { | |
Container, | |
Drawer, | |
Header, | |
Left, | |
Right, | |
Title, | |
Body, | |
Button, | |
Icon | |
} from 'native-base'; | |
//ヘッダー用コンポーネントの宣言 | |
import CommonHeader from './common/CommonHeader'; | |
//ドロワー用コンポーネントの宣言 | |
import SideContents from './SideContents'; | |
/* ・・・(省略)・・・ */ | |
//コンポーネントの内容を定義する ※ ClassComponent | |
class BaseContents extends Component { | |
//コンストラクタ | |
constructor(props) { | |
super(props); | |
//ステートの初期化を行う | |
this.state = { drawerOpen: false, drawerDisabled: false, itemSelected: 'ShopList' }; | |
} | |
//ドロワーメニューを閉じる際に関する設定をする | |
closeDrawer = (item) => { | |
this.setState({itemSelected: item}) | |
this._drawer._root.close() | |
}; | |
//ドロワーメニューを開く際に関する設定をする | |
openDrawer = () => { | |
this._drawer._root.open() | |
}; | |
//ドロワーメニューに対応したシーンの切り替えをする | |
_onItemSelected = (selected) => { | |
switch (selected) { | |
case "ShopList": | |
return <ShopList /> | |
case "ColumnList": | |
return <ColumnList /> | |
case "MyPurchase": | |
return <PurchaseHistory /> | |
case "GithubLink": | |
return <WebView source={{uri: 'https://github.com/fumiyasac/LikeCustomTransition'}} /> | |
case "SlideshareLink": | |
return <WebView source={{uri: 'https://www.slideshare.net/fumiyasakai37/nativebaseui'}} /> | |
default: | |
return <ShopList /> | |
} | |
}; | |
//ドロワーメニューに対応したタイトルの切り替えをする | |
_onTitleSelected = (selected) => { | |
switch (selected) { | |
case "ShopList": | |
return "紹介お店一覧" | |
case "ColumnList": | |
return "コラム一覧" | |
case "MyPurchase": | |
return "Myお買い物" | |
case "GithubLink": | |
return "リポジトリ" | |
case "SlideshareLink": | |
return "スライド" | |
default: | |
return "紹介お店一覧" | |
} | |
}; | |
//コンポーネントの内容をレンダリングする | |
/** | |
* Memo: | |
* NativeBaseのDrawerは下記のライブラリを拡張して作られている | |
* (各種プロパティの参考) React Native Drawer | |
* https://github.com/root-two/react-native-drawer#props | |
*/ | |
render() { | |
return ( | |
<Drawer | |
ref={ (ref) => this._drawer = ref } | |
type={(Platform.OS === 'ios') ? "static" : "overlay"} | |
content={ | |
<SideContents closeDrawer={this.closeDrawer} /> | |
} | |
onOpen={ () => { | |
this.setState({drawerOpen: true}) | |
}} | |
onClose={ () => { | |
this.setState({drawerOpen: false}) | |
}} | |
tweenHandler={ (ratio) => { | |
return { | |
mainOverlay: { opacity: ratio / 2, backgroundColor: 'black' } | |
} | |
}} | |
captureGestures={true} | |
tweenDuration={200} | |
disabled={this.state.drawerDisabled} | |
openDrawerOffset={ (viewport) => { | |
return 80 | |
}} | |
side={"left"} | |
closedDrawerOffset={ () => 0 } | |
panOpenMask={0.04} | |
negotiatePan={true} | |
> | |
<CommonHeader title={this._onTitleSelected(this.state.itemSelected)} icon={"menu"} onPress={ () => this.openDrawer() } /> | |
<Container> | |
{this._onItemSelected(this.state.itemSelected)} | |
</Container> | |
</Drawer> | |
); | |
} | |
} | |
/* ・・・(省略)・・・ */ | |
export default BaseContents; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* コラム一覧ページを表示するコンポーネント | |
*/ | |
import React, { | |
Component | |
} from 'react'; | |
//ReactNativeを使用したコンポーネントの呼び出し | |
import { | |
ScrollView, | |
View, | |
Dimensions | |
} from 'react-native'; | |
//NativeBaseを使用したコンポーネントの呼び出し | |
import { | |
Container, | |
Content, | |
Separator, | |
Text, | |
} from 'native-base'; | |
//react-native-router-fluxのインポート宣言(Actionを使用) | |
import { Actions } from 'react-native-router-flux'; | |
//react-native-snap-carouselのインポート宣言 | |
import Carousel from 'react-native-snap-carousel'; | |
//コラム一覧表示の共通コンポーネントのインポート宣言 | |
import CommonSliderItem from '../common/CommonSliderItem'; | |
import CommonColumnListItem from '../common/CommonColumnListItem'; | |
//表示データの読み込み | |
import { getSliderList, getArchiveList } from '../../stub/SampleDataStub'; | |
//デバイスのサイズ取得 | |
const { | |
width: DEVICE_WIDTH, | |
} = Dimensions.get('window'); | |
//ギャラリーの幅と高さの設定 | |
const sliderWidth = DEVICE_WIDTH; | |
const sliderHeight = DEVICE_WIDTH / 2; | |
//コンポーネントの内容を定義する ※ ClassComponent | |
class ColumnList extends Component { | |
//スライド用のコンポーネントを組み立てる処理 | |
_getSlides() { | |
return getSliderList().map((slider, index) => { | |
return ( | |
<CommonSliderItem key={index} slider={slider} onPress={ () => console.log("_getSlides() : Work In Progress.") } /> | |
); | |
}); | |
} | |
//リスト用のコンポーネントを組み立てる処理 | |
_getArchives() { | |
return getArchiveList().map((archive, index) => { | |
return ( | |
<CommonColumnListItem key={index} archive={archive} onPress={ () => console.log("_getArchives() : Work In Progress.") } /> | |
); | |
}); | |
} | |
//コンポーネントの内容をレンダリングする | |
render() { | |
return ( | |
<Container style={styles.backgroundContainer}> | |
{/* 1. スライドメニュー */} | |
<View style={styles.containerWrappedViewStyle}> | |
<Carousel | |
ref={(carousel) => { this._carousel = carousel; }} | |
sliderWidth={sliderWidth} | |
itemWidth={sliderWidth} | |
firstItem={0} | |
inactiveSlideScale={0.86} | |
inactiveSlideOpacity={0.38} | |
enableMomentum={false} | |
containerCustomStyle={styles.containerCustomStyle} | |
contentContainerCustomStyle={styles.contentContainerCustomStyle} | |
showsHorizontalScrollIndicator={false} | |
snapOnAndroid={true} | |
> | |
{/* スライド用のコンテンツを表示する */} | |
{this._getSlides()} | |
</Carousel> | |
</View> | |
{/* 2. アーカイブ部分 */} | |
<ScrollView> | |
<Content> | |
<Separator bordered> | |
<Text>過去のアーカイブ</Text> | |
</Separator> | |
{/* アーカイブ用のコンテンツを表示する */} | |
{this._getArchives()} | |
</Content> | |
<Separator bordered> | |
<Text>コラムについて</Text> | |
</Separator> | |
<Text style={styles.backgroundDescription}> | |
歴史がありながらも最近の発展やまちづくりにも目覚ましい下町情緒が溢れるあたたかな街、大塚。 | |
オフィス街・地域のお祭り・ライブハウス・隠れ家的な名店等、様々な表情をこの街は見せてくれます。 | |
</Text> | |
</ScrollView> | |
</Container> | |
); | |
} | |
} | |
//このコンポーネントのスタイル設定 | |
const styles = { | |
backgroundContainer: { | |
backgroundColor: '#fff', | |
}, | |
backgroundDescription: { | |
color: '#666', | |
textAlign: 'left', | |
fontSize: 14, | |
marginTop: 16, | |
marginLeft: 16, | |
marginRight: 16, | |
marginBottom: 16, | |
lineHeight: 20, | |
}, | |
buttonTextStyle: { | |
fontSize: 13, | |
fontWeight: 'bold', | |
textAlign: 'center', | |
color: '#fff', | |
}, | |
containerWrappedViewStyle: { | |
height: sliderHeight, | |
}, | |
contentContainerCustomStyle: { | |
height: sliderHeight, | |
}, | |
}; | |
//インポート可能にする宣言 | |
export default ColumnList; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'react-native'; | |
import React from 'react'; | |
import CommonCard from '../../../src/components/common/CommonCard'; | |
// Note: test renderer must be required after react-native. | |
import renderer from 'react-test-renderer'; | |
test('共通コンポーネント(店舗表示用部分)のスナップショットテスト', () => { | |
const shopDataMock = jest.fn(); | |
shopDataMock.mockReturnValue( | |
{"shops":{ | |
"contents":[ | |
{ | |
"id":"1", | |
"title":"大塚の油そば「麺屋 帝旺」", | |
"category":"ラーメン・油そば","kcpy":"ピリ辛の特製ラー油がうまさの秘訣!", | |
"detail":"少しピリ辛のラー油と食べ応えのある太麺が一度食べるとやみつきになる一品です。", | |
"image_url":"https://otsuka-shop.s3-ap-northeast-1.amazonaws.com/shops/images/1/large.jpg"} | |
] | |
}} | |
); | |
const tree = renderer.create( | |
<CommonCard shop={shopDataMock().shops.contents[0]} onPress={ () => console.log("テスト") } /> | |
).toJSON(); | |
expect(tree).toMatchSnapshot(); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* コメント表示用UIのベース部分を表示するコンポーネント | |
*/ | |
import React from 'react'; | |
//ReactNativeを使用したコンポーネントの呼び出し | |
import { | |
StyleSheet, | |
} from 'react-native'; | |
//NativeBaseを使用したコンポーネントの呼び出し | |
import { | |
ListItem, | |
Left, | |
Body, | |
Right, | |
Text, | |
Thumbnail | |
} from 'native-base'; | |
//一覧シンプルリスト表示用のベースコンポーネントの内容を定義する | |
const CommonComment = ({ comment }) => { | |
//取得した引数(オブジェクト:{ comment })を分割する | |
const { id, title, description, image_url, time } = comment; | |
//表示する要素を返す | |
return ( | |
<ListItem avatar> | |
<Left> | |
<Thumbnail source={image_url} /> | |
</Left> | |
<Body> | |
<Text>{title}</Text> | |
<Text style={styles.commentTextStyle} note>{description}</Text> | |
</Body> | |
<Right> | |
<Text note>{time}</Text> | |
</Right> | |
</ListItem> | |
); | |
}; | |
//このコンポーネントのスタイル設定 | |
const styles = { | |
commentTextStyle: { | |
marginTop: 8, | |
fontSize: 14, | |
lineHeight: 18 | |
}, | |
}; | |
//このコンポーネントをインポート可能にする | |
export default CommonComment; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 共通ヘッダーのUI部分を表示するコンポーネント | |
*/ | |
import React from 'react'; | |
//ReactNativeを使用したコンポーネントの呼び出し | |
import { | |
StyleSheet, | |
} from 'react-native'; | |
//NativeBaseを使用したコンポーネントの呼び出し | |
import { | |
Header, | |
Left, | |
Right, | |
Body, | |
Title, | |
Button, | |
Icon, | |
} from 'native-base'; | |
//ヘッダー用のベースコンポーネントの内容を定義する | |
const CommonHeader = ({ title, icon, onPress }) => { | |
//表示する要素を返す | |
return ( | |
<Header iosBarStyle="light-content" style={styles.headerBackStyle} hasTabs> | |
<Left> | |
<Button transparent onPress={onPress}> | |
<Icon style={styles.backStyle} name={icon || "arrow-back"} /> | |
</Button> | |
</Left> | |
<Body> | |
<Title style={styles.titleStyle}>{title}</Title> | |
</Body> | |
<Right /> | |
</Header> | |
); | |
}; | |
//このコンポーネントのStyle定義 | |
const styles = { | |
headerBackStyle: { | |
backgroundColor: '#000', | |
}, | |
backStyle: { | |
color: '#fff', | |
}, | |
titleStyle: { | |
color: '#fff', | |
}, | |
}; | |
//このコンポーネントをインポート可能にする | |
export default CommonHeader; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ npm install native-base --save | |
$ react-native link |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sakaifumiyanoMacBook-Pro:LikeCustomTransition sakaifumiya$ npm test CommonCard.js --no-cache | |
> [email protected] test /Users/sakaifumiya/Desktop/reactNativeApp/LikeCustomTransition | |
> jest "CommonCard.js" | |
FAIL __tests__/src/common/CommonCard.js | |
● Test suite failed to run | |
ENOENT: no such file or directory, stat '/Users/sakaifumiya/Desktop/reactNativeApp/LikeCustomTransition/node_modules/react-native-router-flux/node_modules/react-native/Libraries/Core/ErrorUtils.js' | |
at Object.fs.statSync (fs.js:968:11) | |
at Object.statSync (node_modules/graceful-fs/polyfills.js:297:22) | |
at Object.<anonymous> (node_modules/react-native/jest/setup.js:64:532) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Icon ios='ios-pizza' android="md-pizza" style={{color: '#ffc125'}}/> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* フォトギャラリー画面を表示するコンポーネント | |
*/ | |
import React, { | |
Component | |
} from 'react'; | |
//ReactNativeを使用したコンポーネントの呼び出し | |
import { | |
StyleSheet, | |
View, | |
Image, | |
Dimensions | |
} from 'react-native'; | |
//NativeBaseを使用したコンポーネントの呼び出し | |
import { | |
Container, | |
Content, | |
Header, | |
Text | |
} from 'native-base'; | |
//幅と高さを取得する | |
const { | |
width: DEVICE_WIDTH | |
} = Dimensions.get('window'); | |
//グリッドの幅調整用の値 | |
const gridWidth = DEVICE_WIDTH / 2 - 15; | |
//共通ヘッダーのインポート宣言 | |
import CommonHeader from './common/CommonHeader'; | |
//グリッド表示用のライブラリのインポート宣言(NativeBaseのグリッドを使わない) | |
import GridView from 'react-native-super-grid'; | |
//表示データの読み込み | |
import { getGalleryList } from '../stub/SampleDataStub'; | |
//react-native-router-fluxのインポート宣言(Actionを使用) | |
import { Actions } from 'react-native-router-flux'; | |
//コンポーネントの内容を定義する ※ ClassComponent | |
class PhotoGalleryContents extends Component { | |
//コンポーネントの内容をレンダリングする | |
/** | |
* Memo: | |
* | |
*/ | |
render() { | |
//コンポーネントのレンダリング | |
return ( | |
<Container> | |
<CommonHeader title={"フォト一覧"} onPress={ () => Actions.pop() } /> | |
<Content> | |
{/* iOSでのUICollectionViewの様なレイアウト */} | |
<GridView | |
itemWidth={130} | |
items={getGalleryList()} | |
style={styles.gridViewStyle} | |
renderItem={ item => ( | |
<Image style={styles.itemContainerStyle} source={{ uri: item.gallery }}> | |
<Text style={styles.itemNameStyle}>{item.name}</Text> | |
<Text style={styles.itemDateStyle}>{item.date}</Text> | |
</Image> | |
) } | |
/> | |
</Content> | |
</Container> | |
); | |
} | |
} | |
//このコンポーネントのスタイル設定 | |
const styles = { | |
gridViewStyle: { | |
paddingTop: 10, | |
flex: 1, | |
}, | |
itemContainerStyle: { | |
justifyContent: 'flex-end', | |
borderRadius: 5, | |
padding: 10, | |
height: 150, | |
width: gridWidth, | |
}, | |
itemNameStyle: { | |
fontSize: 16, | |
color: '#fff', | |
fontWeight: '600', | |
}, | |
itemDateStyle: { | |
fontWeight: '600', | |
fontSize: 12, | |
color: '#fff', | |
}, | |
}; | |
//このコンポーネントをインポート可能にする | |
export default PhotoGalleryContents; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* お買い物履歴を表示するコンポーネント | |
*/ | |
import React, { | |
Component | |
} from 'react'; | |
//ReactNativeを使用したコンポーネントの呼び出し | |
import { | |
StyleSheet, | |
} from 'react-native'; | |
//NativeBaseを使用したコンポーネントの呼び出し | |
import { | |
Container, | |
Content, | |
} from 'native-base'; | |
//react-native-router-fluxのインポート宣言(Actionを使用) | |
import { Actions } from 'react-native-router-flux'; | |
//react-native-timeline-listviewのインポート宣言 | |
import Timeline from 'react-native-timeline-listview'; | |
//表示データの読み込み | |
import { getPurchaseHistory } from '../../stub/SampleDataStub'; | |
//コンポーネントの内容を定義する ※ ClassComponent | |
class PurchaseHistory extends Component { | |
//コンポーネントの内容をレンダリングする | |
/** | |
* Memo: | |
* | |
*/ | |
render() { | |
//コンポーネントのレンダリング | |
return ( | |
<Container style={styles.backgroundContainer}> | |
<Content style={styles.backgroundDescription}> | |
<Timeline | |
innerCircle={'dot'} | |
timeStyle={styles.timeStyle} | |
descriptionStyle={styles.descriptionStyle} | |
data={getPurchaseHistory()} | |
/> | |
</Content> | |
</Container> | |
); | |
} | |
} | |
//このコンポーネントのスタイル設定 | |
const styles = { | |
backgroundContainer: { | |
backgroundColor: '#fff', | |
}, | |
backgroundDescription: { | |
paddingTop: 16, | |
paddingLeft: 16, | |
paddingRight: 16, | |
paddingBottom: 16, | |
}, | |
timeStyle: { | |
textAlign: 'center', | |
backgroundColor: '#999', | |
fontSize: 12, | |
fontWeight: 'bold', | |
color: '#fff', | |
padding: 5, | |
}, | |
descriptionStyle: { | |
color:'#666', | |
lineHeight: 18, | |
} | |
}; | |
//このコンポーネントをインポート可能にする | |
export default PurchaseHistory; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
//NativeBaseを使用したコンポーネントの呼び出し | |
import { | |
Container, | |
Header, | |
Title, | |
Content, | |
Footer, | |
Button, | |
Left, | |
Right, | |
Body, | |
Icon, | |
} from 'native-base'; | |
| |
//ヘッダー・コンテンツ・フッター表示の基本形 | |
class Sample extends Component { | |
//見た目部分のレンダリングを行う | |
render() { | |
return ( | |
<Container> | |
{/* ヘッダー表示部分 */} | |
<Header> | |
<Left> | |
<Button transparent onPress={ () => console.log("MenuButtonTapped!") }> | |
<Icon name='menu' /> | |
</Button> | |
</Left> | |
<Body> | |
<Title>Header</Title> | |
</Body> | |
<Right /> | |
</Header> | |
{/* コンテンツ表示部分 */} | |
<Content> | |
ここにコンテンツを色々表示する形になります。 | |
</Content> | |
{/* フッター表示部分 */} | |
<Footer> | |
<Button active> | |
<Icon ios='ios-paper' android="md-paper" /> | |
<Text style={styles.footerTextStyle}>フィード</Text> | |
</Button> | |
<Button> | |
<Icon ios='ios-bookmark' android="md-bookmark" /> | |
<Text style={styles.footerTextStyle}>お気に入り</Text> | |
</Button> | |
<Button> | |
<Icon ios='ios-map' android="md-map" /> | |
<Text style={styles.footerTextStyle}>地図</Text> | |
</Button> | |
<Button badge> | |
<Badge><Text>20+</Text></Badge> | |
<Icon ios='ios-mail' android="md-mail" /> | |
<Text style={styles.footerTextStyle}>メール</Text> | |
</Button> | |
</Footer> | |
</Container> | |
); | |
} | |
} | |
//このコンポーネントをインポート可能にする | |
export default Sample; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* お店の詳細を表示するコンポーネント | |
*/ | |
//・・・(省略)・・・ | |
//react-native-easy-gridのコンポーネントの呼び出し | |
import { | |
Col, | |
Row, | |
Grid | |
} from 'react-native-easy-grid'; | |
//デバイスのサイズ取得 | |
const { | |
width: DEVICE_WIDTH, | |
height: DEVICE_HEIGHT | |
} = Dimensions.get('window'); | |
//ギャラリーの幅と高さの設定 | |
const mainAreaWidth = DEVICE_WIDTH - 120; | |
const mainAreaHeight = 120 * 2; | |
const subAreaRect = 120; | |
//・・・(省略)・・・ | |
//コンポーネントの内容を定義する ※ ClassComponent | |
class ShopInfo extends Component { | |
//コンポーネントの内容をレンダリングする | |
/** | |
* Memo: | |
* | |
*/ | |
render() { | |
return ( | |
<Container> | |
<ScrollView> | |
<Content> | |
{/* ・・・(省略)・・・ */} | |
{/* 2. 画像表示エリア */} | |
<View> | |
<Content> | |
<Grid> | |
<Col style={styles.firstImageStyle}> | |
<Image style={styles.firstImageStyle} source={require('../../assets/detail1.jpg')} /> | |
</Col> | |
<Col> | |
<Row style={styles.secondImageStyle}> | |
<Image style={styles.secondImageStyle} source={require('../../assets/detail2.jpg')} /> | |
</Row> | |
<Row style={styles.thirdImageStyle}> | |
<Image style={styles.thirdImageStyle} source={require('../../assets/detail3.jpg')} /> | |
</Row> | |
</Col> | |
</Grid> | |
</Content> | |
</View> | |
{/* ・・・(省略)・・・ */} | |
</Content> | |
</ScrollView> | |
</Container> | |
); | |
} | |
} | |
//このコンポーネントのスタイル設定 | |
const styles = { | |
/* ・・・(省略)・・・ */ | |
firstImageStyle: { | |
width: mainAreaWidth, | |
height: mainAreaHeight, | |
}, | |
secondImageStyle: { | |
width: subAreaRect, | |
height: subAreaRect, | |
}, | |
thirdImageStyle: { | |
width: subAreaRect, | |
height: subAreaRect, | |
}, | |
}; | |
//このコンポーネントをインポート可能にする | |
export default ShopInfo; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* お店一覧を表示するコンポーネント | |
*/ | |
import React, { | |
Component | |
} from 'react'; | |
//ReactNativeを使用したコンポーネントの呼び出し | |
import { | |
ScrollView, | |
View, | |
Text, | |
} from 'react-native'; | |
//NativeBaseを使用したコンポーネントの呼び出し | |
import { | |
Spinner, | |
Button, | |
} from 'native-base'; | |
//アルバム詳細用の共通コンポーネントのインポート宣言 | |
import CommonCard from '../common/CommonCard'; | |
//react-native-router-fluxのインポート宣言(Actionを使用) | |
import { Actions } from 'react-native-router-flux'; | |
//HTTP通信用のライブラリ'axios'のインポート宣言 | |
import axios from 'axios'; | |
//コンポーネントの内容を定義する ※ ClassComponent | |
class ShopList extends Component { | |
//コンストラクタ | |
constructor(props) { | |
super(props); | |
//ステートの初期化を行う | |
this.state = { shops: [], isLoading: true, isError: false, modalVisible: false }; | |
} | |
//ショップデータをフェッチする | |
fetchShopData() { | |
//Memo: 自作APIとバインドする(ここはRails4.1.7で構築) | |
axios.get('https://rocky-dusk-33235.herokuapp.com/shops.json') | |
.then(response => this.setState({ shops: response.data.shops.contents, isLoading: false })) | |
.catch(error => this.setState({ shops: [], isLoading: false, isError: true })); | |
} | |
//ショップデータの再読み込みを行う | |
reloadShops() { | |
this.state = { shops: [], isLoading: true, isError: false }; | |
this.fetchShopData(); | |
} | |
//ショップデータのレンダリングを行う | |
renderShops() { | |
return this.state.shops.map(shop => | |
<CommonCard key={shop.id} shop={shop} onPress={ () => Actions.ShopDetailContents({id: shop.id, title: "お店詳細"}) } /> | |
); | |
} | |
//コンポーネントの内容がMountされる前に行う処理 | |
componentWillMount() { | |
this.fetchShopData(); | |
} | |
//コンポーネントの内容をレンダリングする | |
render() { | |
//ローデーィング時 | |
if (this.state.isLoading) { | |
return ( | |
<View style={styles.spinnerWrapperStyle}> | |
<Spinner color="#666" /> | |
<Text style={styles.spinnerInnerText}>データ取得中...</Text> | |
</View> | |
); | |
} | |
//エラー発生時 | |
if (this.state.isError) { | |
return ( | |
<View style={styles.spinnerWrapperStyle}> | |
<Text style={styles.spinnerInnerTextStyle}>エラー:データを取得できませんでした。</Text> | |
<View> | |
<Button style={styles.buttonStyle} onPress={ () => this.reloadShops() } dark> | |
<Text style={styles.buttonTextStyle}>再度データを取得する</Text> | |
</Button> | |
</View> | |
</View> | |
); | |
} | |
//正常処理時 | |
return ( | |
<ScrollView style={styles.backgroundContainer}> | |
{this.renderShops()} | |
</ScrollView> | |
); | |
} | |
} | |
//このコンポーネントのスタイル設定 | |
const styles = { | |
backgroundContainer: { | |
backgroundColor: '#fff', | |
}, | |
spinnerWrapperStyle: { | |
flex: 1, | |
backgroundColor: '#fff', | |
justifyContent: 'center', | |
alignItems: 'center', | |
}, | |
spinnerInnerTextStyle: { | |
fontSize: 13, | |
textAlign: 'center', | |
color: '#666', | |
}, | |
buttonStyle: { | |
marginTop: 10, | |
alignItems: 'center', | |
}, | |
buttonTextStyle: { | |
fontSize: 13, | |
fontWeight: 'bold', | |
textAlign: 'center', | |
color: '#fff', | |
}, | |
}; | |
//インポート可能にする宣言 | |
export default ShopList; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* サイドコンテンツ用のコンポーネント | |
*/ | |
import React, { | |
Component, | |
PropTypes | |
} from 'react'; | |
//ReactNativeを使用したコンポーネントの呼び出し | |
import { | |
StyleSheet, | |
View, | |
Image, | |
Text, | |
Dimensions | |
} from 'react-native'; | |
//NativeBaseを使用したコンポーネントの呼び出し | |
import { | |
Container, | |
Button, | |
Content, | |
ListItem, | |
Separator, | |
Icon | |
} from 'native-base'; | |
//幅と高さを取得する | |
const { | |
width: DEVICE_WIDTH, | |
height: DEVICE_HEIGHT | |
} = Dimensions.get('window'); | |
//コンポーネントの内容を定義する ※ ClassComponent | |
class SideContents extends Component { | |
//このコンポーネントのpropTypesの定義(this.propsで受け取れる情報に関するもの) | |
static propTypes = { | |
closeDrawer: PropTypes.func.isRequired, | |
}; | |
//コンポーネントの内容をレンダリングする | |
/** | |
* Memo: アイコン選定の参考はこちら | |
* https://github.com/oblador/react-native-vector-icons | |
* https://oblador.github.io/react-native-vector-icons/ | |
*/ | |
render() { | |
return ( | |
<Container style={styles.containerBackgroundStyle}> | |
<View style={styles.containerHeaderStyle}> | |
<Image style={styles.containerHeaderImageStyle} source={require('../assets/otsuka_sample.jpg')} /> | |
<View style={styles.overlayStyle}> | |
<Text style={styles.overlayTextStyle}>大塚Deお買い物Menu</Text> | |
</View> | |
</View> | |
<Content> | |
{/* ドロワーメニューでのメニュー部分(コンポーネント表示切り替え) */} | |
<Separator bordered> | |
<Text>コンテンツ</Text> | |
</Separator> | |
<ListItem onPress={ () => {this.props.closeDrawer("ShopList")} }> | |
<Icon ios='ios-pizza' android="md-pizza" style={{color: '#ffc125'}}/> | |
<Text style={styles.menuTextStyle}>紹介お店一覧</Text> | |
</ListItem> | |
<ListItem onPress={ () => {this.props.closeDrawer("ColumnList")} }> | |
<Icon ios='ios-book' android="ios-book" style={{color: '#ff6600'}}/> | |
<Text style={styles.menuTextStyle}>コラム一覧</Text> | |
</ListItem> | |
<ListItem onPress={ () => {this.props.closeDrawer("MyPurchase")} } last> | |
<Icon ios='ios-cart' android="md-cart" style={{color: '#ff3333'}}/> | |
<Text style={styles.menuTextStyle}>Myお買い物</Text> | |
</ListItem> | |
{/* ドロワーメニューでのメニュー部分(WebViewでの表示) */} | |
<Separator bordered> | |
<Text>このサンプルに関して</Text> | |
</Separator> | |
<ListItem onPress={ () => {this.props.closeDrawer("GithubLink")} }> | |
<Icon ios='logo-octocat' android="logo-octocat" style={{color: '#333333'}}/> | |
<Text style={styles.menuTextStyle}>Githubへのリンク</Text> | |
</ListItem> | |
<ListItem onPress={ () => {this.props.closeDrawer("SlideshareLink")} }> | |
<Icon ios='logo-linkedin' android="logo-linkedin" style={{color: '#0077b5'}}/> | |
<Text style={styles.menuTextStyle}>SlideShareへのリンク</Text> | |
</ListItem> | |
</Content> | |
</Container> | |
); | |
} | |
} | |
/* ・・・(省略)・・・ */ | |
//インポート可能にする宣言 | |
export default SideContents; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment