[React Native] タブナビゲーション+FlatListサンプル

# つくったもの
汎用的に使えるようタブナビゲーションによるページ切り替えと配列要素をFlatListを利用して表示できるサンプルを作りました。

# 環境
□expo cli
こちらに関しては下記記事で環境構築できます
[【React Native】 Expoを使えば審査なしにアプリ更新出来てウハウハなのか？](https://qiita.com/keneo/items/625c7623d0dfb0cf0c6c)

□react-native-elements

```
$ npm add react-native-elements
```

□react navigation
今回はタブナビゲーション（スマホアプリでよく見るボトムボタン）によるページ切り替えを導入

```json:package.json
  "dependencies": {
    省略
    "react-navigation": "2.11.2"
  },
```

```
$ npm install
```

# シンプルなタブナビゲーションとリスト表示

```App.js
import React, { Component } from 'react';
import { StyleSheet, FlatList, Alert, Modal, Button, StatusBar, TextInput, ScrollView, Text, View, Image } from 'react-native';
import { Header, Tile } from 'react-native-elements';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';

// HomeScreen
class HomeScreen extends Component {
    items = [
        { id: 1, name: 'User A', mail: 'example_a@example.com', message: 'Aです' },
        { id: 2, name: 'User B', mail: 'example_b@example.com', message: 'Bです' },
        // 追加
    ];

    constructor(props) {
        super(props);
        this.state = {
            title: 'Home Screen',
            message: '',
        }
    }

    render() {
        return (   
            <View style={styles.base}>
                <View style={ styles.body }>
                    <Text>{ this.state.message }</Text>
                    <FlatList 
                        data={ this.items }
                        renderItem={ this.getItem }
                        keyExtractor={(item, index) => index.toString()}
                    />
                    {/* <Image style={styles.mainImage} source={ require('./assets/ph1.jpg') } /> */}
                </View>
            </View>
        );
    }

    getItem = ({ item }) => {
        return (
            <View>
                <Text
                    onPress={ () => this.doAction(item) }
                >
                    { item.id }: { item.name }({ item.mail })
                </Text>
            </View>
        );
    }
    
    doAction = (item) => {
        this.setState({
            selected: item.id * 1,
            message: item.message.toString()
        });
    }
}

// UserScreen
class UserScreen extends Component {
    constructor(props) {
        super(props);
        this.state = {
            title: 'User Screen',
            message: 'This is User Screen.',
        }
    }

    render() {
        return (
        <View style={styles.base}>
            <View style={ styles.body }>
                <Text>{ this.state.title }</Text>
                <Text>{ this.state.message }</Text>
            </View>
        </View>
        );
    }
} // UserScreen

const TabNavigator = createBottomTabNavigator (
    {
        Home: {
            screen: HomeScreen,
            navigationOptions: {
                tabBarIcon: ({ tintColor }) => <Image source={require('./assets/home.png')} style={{ width: 20, height: 20, tintColor: tintColor }} />,
                title: 'ホーム'
            }
        },
        User: {
            screen: UserScreen,
            navigationOptions: {
                tabBarIcon: ({ tintColor }) => <Image source={require('./assets/user.png')} style={{ width: 20, height: 20, tintColor: tintColor }} />,
                title: 'ユーザー'
            }
        },
    },
    {
        tabBarOptions: {
            activeTintColor: '#DC5654',
            inactiveTintColor: '#a9a9a9',
            activeBackgroundColor: '#fff',
            inactiveBackgroundColor: '#eee',
            labelStyle: {
                fontSize: 14,
            },
        }
    }
);

export default class AppScreen extends Component {
    render() {
        return(
        <View style={ styles.base }>
            <Header
                centerComponent={{
                    text: 'Instagram',
                    style: styles.header
                }}
                otherContainerStyles={{
                    height: 100,
                    backgroundColor: '#dd0000'
                }}
                innerContainerStyles={{
                    height: 100,
                    backgroundColor: '#dd0000'
                }}
                />
            <TabNavigator />
        </View>
        );
    }
}

const styles = StyleSheet.create ({
    base: {
        padding: 0,
        flex: 1,
    },
    body: {
        backgroundColor: '#fff',
    },
    header: {
        color: '#fff',
        fontSize: 20,
        fontWeight: '500',
    },
    mainImage: {
        width: '100%',
        height: 300,
    }
});
```

# [応用]SNS風デザイン

![スクリーンショット 2020-01-26 2.16.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/a9c8c4c8-7204-7a7e-29a2-1f7595f6553a.png)

使っている画像一覧（計5点）
assets/images/
|- thumbnail.png
|- ph1.jpg
|- ph2.jpg
|- home.png
|- user.png

上記ファイルをassetsフォルダに入れる
その他、追加したり変更も可能です。

```App.js
import React, { Component } from 'react';
import { StyleSheet, FlatList, Alert, Modal, Button, StatusBar, TextInput, ScrollView, Text, View, Image } from 'react-native';
import { Header, Tile } from 'react-native-elements';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';

// HomeScreen
class HomeScreen extends Component {
    items = [
        { 
            id: 1,
            name: 'Member',
            mail: 'example_a@example.com',
            thumbnail: require('./assets/images/thumbnail.png'),
            title: '兵庫県公館『1995.1.17から25年 振り返る阪神・淡路大震災』 神戸市中央区',
            message: '　兵庫県公館県政資料館（神戸市中央区）で現在、特別展示『1995.1.17から25年 振り返る阪神・淡路大震災』が開催されている。2月15日まで。入館無料。',
            mainImage: require('./assets/images/ph1.jpg')
        },
        { 
            id: 2,
            name: 'Admin', 
            mail: 'example_b@example.com', 
            thumbnail: require('./assets/images/thumbnail.png'),
            title: 'ザ・ガーデン・プレイス蘇州園『SOSHUEN RED Aftrenoon Tea』神戸市東灘区',
            message: '　昭和9年に建築され、現在は結婚式場・レストランとして営業するザ・ガーデン・プレイス蘇州園（神戸市東灘区）で2月5日より『SOSHUEN RED Aftrenoon Tea』が開催される。3月16日まで。',
            mainImage: require('./assets/images/ph2.jpg')
        },
    ];

    constructor(props) {
        super(props);
        this.state = {
            title: 'Home Screen',
        }
    }

    render() {
        return (   
            <View style={styles.base}>
                <View style={ styles.body }>
                    <FlatList 
                        data={ this.items }
                        renderItem={ this.getItem }
                        keyExtractor={(item, index) => index.toString()}
                    />
                </View>
            </View>
        );
    }

    getItem = ({ item }) => {
        return (
            <View style={ styles.postWrap }>
                <View style={ styles.userWrap }>
                    <Image style={ styles.thumbnail } source={ item.thumbnail } />
                    <Text
                        style={ styles.userName }
                        onPress={ () => this.doAction(item) }
                    >
                        { item.name }
                    </Text>
                </View>
                <Image style={ styles.mainImage } source={ item.mainImage } />
                <Text style={ styles.title }>{ item.title }</Text>
                <Text style={ styles.message }>{ item.message }</Text>
            </View>
        );
    }
    
    doAction = (item) => {
        this.setState({
            selected: item.id * 1,
            title: item.title.toString()
        });
    }
}

// UserScreen
class UserScreen extends Component {
    constructor(props) {
        super(props);
        this.state = {
            title: 'User Screen',
        }
    }

    render() {
        return (
        <View style={styles.base}>
            <View style={ styles.body }>
                <Text>{ this.state.title }</Text>
                <Text>{ this.state.message }</Text>
            </View>
        </View>
        );
    }
} // UserScreen

const TabNavigator = createBottomTabNavigator (
    {
        Home: {
            screen: HomeScreen,
            navigationOptions: {
                tabBarIcon: ({ tintColor }) => <Image source={require('./assets/images/home.png')} style={{ width: 20, height: 20, tintColor: tintColor }} />,
                title: 'ホーム'
            }
        },
        User: {
            screen: UserScreen,
            navigationOptions: {
                tabBarIcon: ({ tintColor }) => <Image source={require('./assets/images/user.png')} style={{ width: 20, height: 20, tintColor: tintColor }} />,
                title: 'ユーザー'
            }
        },
    },
    {
        tabBarOptions: {
            activeTintColor: '#DC5654',
            inactiveTintColor: '#a9a9a9',
            activeBackgroundColor: '#fff',
            inactiveBackgroundColor: '#eee',
            labelStyle: {
                fontSize: 14,
            },
        }
    }
);

export default class AppScreen extends Component {
    render() {
        return(
        <View style={ styles.base }>
            <Header
                centerComponent={{
                    text: 'Instagram',
                    style: styles.header
                }}
                otherContainerStyles={{
                    height: 100,
                    backgroundColor: '#dd0000'
                }}
                innerContainerStyles={{
                    height: 100,
                    backgroundColor: '#dd0000'
                }}
            />
            <TabNavigator />
        </View>
        );
    }
}

const styles = StyleSheet.create ({
    base: {
        padding: 0,
        flex: 1,
    },
    body: {
        backgroundColor: '#fff',
    },
    header: {
        color: '#fff',
        fontSize: 20,
        fontWeight: '500',
    },
    postWrap: {
        marginTop: 25,
        borderBottomWidth: 1,
        borderColor:'#ccc',
    },
    userWrap: {
        flexDirection: 'row',
        alignItems: 'center',
    },
    userName: {
        fontSize: 20,
        fontWeight: '500',
        marginLeft: 15,
    },
    title: {
        color: '#DC5654',
        fontSize: 20,
        fontWeight: '500',
        textAlign: 'justify',
        lineHeight: 25,
        marginLeft: 15,
        marginRight: 15,
        marginBottom: 10,
    },
    message: {
        color: '#000',
        fontSize: 18,
        fontWeight: '300',
        textAlign: 'justify',
        lineHeight: 28,
        marginLeft: 15,
        marginRight: 15,
        marginBottom: 25,
    },
    thumbnail: {
        width: 75,
        height: 75,
        marginLeft: 10,
        marginBottom: 10,
        borderRadius: 100,
    },
    mainImage: {
        width: '100%',
        height: 300,
        marginBottom: 20,
    }
});
```
# あとがき
こちらでデザインまではネイティブアプリで作ることができました。
今後はFirebaseを利用して投稿、表示などができればSNS系のアプリになるので
ここを目指していきたい。

あとTOPのヘッダー部分（現在青くなってる部分）の色変えは調査中。
わかり次第追記予定。