react-nativeでタブナビゲーションを実装
作成したやつ
参考情報
React Navigationのタブナビゲーションをカスタマイズしてみよう! - bagelee(ベーグリー) createMaterialTopTabNavigator | React Navigation
github
react-native_samples/sampleAppNavigation01 at main · mshige1979/react-native_samples · GitHub
コード全体
/** * Sample React Native App * https://github.com/facebook/react-native * * @format * @flow strict-local */ import React, {useState} from 'react'; import {View, StyleSheet, StatusBar, Platform} from 'react-native'; import {NavigationContainer} from '@react-navigation/native'; import {createMaterialTopTabNavigator} from '@react-navigation/material-top-tabs'; // タブエリア import AppTabBar from './src/components/AppTabBar'; // サンプルページ import Home from './src/screens/home'; import Profile from './src/screens/profile'; import MyPage from './src/screens/mypage'; // タブコンポーネント const TopTabs = createMaterialTopTabNavigator(); const TopTabsScreen = () => { const [swipeEnabled, setSwipeEnabled] = useState(true); // Profileの場合は左右にスワイプする // Profile以外の場合はスワイプしない // 参考:https://stackoverflow.com/questions/63611393/react-native-material-top-tab-navigator-swipe-disable-depending-on-screens const focusCheck = ({navigation, route}) => ({ focus: () => { console.log('focus: ', route.name); setSwipeEnabled(route.name === 'Profile'); }, }); return ( <TopTabs.Navigator swipeEnabled={swipeEnabled} // スワイプによる移動を制御(true: スワイプ移動、false: 移動しない) tabBar={(props) => <AppTabBar {...props} />} style={{ marginTop: Platform.select({ ios: 50, android: 0, }), }}> <TopTabs.Screen name="Home" component={Home} listeners={focusCheck} /> <TopTabs.Screen name="Profile" component={Profile} listeners={focusCheck} /> <TopTabs.Screen name="MyPage" component={MyPage} listeners={focusCheck} /> </TopTabs.Navigator> ); }; // メイン const App = () => { return ( <> <NavigationContainer> <TopTabsScreen /> </NavigationContainer> <StatusBar barStyle="dark-content" /> </> ); }; const styles = StyleSheet.create({}); export default App;
1.画面を作成
import React, {useEffect} from 'react'; import {View, Text, StyleSheet, Button} from 'react-native'; const Home = ({navigation, route}) => { return ( <View style={styles.container}> <View> <Text>Home</Text> </View> <View style={{ margin: 10, }}> <Text>Topタブのサンプル このタブはスワイプしない</Text> </View> <View> <Button title="Profileへ移動" onPress={() => { navigation.jumpTo('Profile'); }} /> </View> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); export default Home;
こーいうものを作成する
2. タブコンポーネントを作成
1で作成したコンポーネントを設定する。 基本2〜5位がちょうどいい感じ
// タブコンポーネント const TopTabs = createMaterialTopTabNavigator(); const TopTabsScreen = () => { const [swipeEnabled, setSwipeEnabled] = useState(true); // Profileの場合は左右にスワイプする // Profile以外の場合はスワイプしない // 参考:https://stackoverflow.com/questions/63611393/react-native-material-top-tab-navigator-swipe-disable-depending-on-screens const focusCheck = ({navigation, route}) => ({ focus: () => { console.log('focus: ', route.name); setSwipeEnabled(route.name === 'Profile'); }, }); return ( <TopTabs.Navigator swipeEnabled={swipeEnabled} // スワイプによる移動を制御(true: スワイプ移動、false: 移動しない) tabBar={(props) => <AppTabBar {...props} />} style={{ marginTop: Platform.select({ ios: 50, android: 0, }), }}> <TopTabs.Screen name="Home" component={Home} listeners={focusCheck} /> <TopTabs.Screen name="Profile" component={Profile} listeners={focusCheck} /> <TopTabs.Screen name="MyPage" component={MyPage} listeners={focusCheck} /> </TopTabs.Navigator> ); };
swipeEnabled
⇨ 左右にスワイプするための設定値、trueでスワイプする、falseでしない
フォーカスイベントで任意の画面のみスワイプするように制御可能
// Profileの場合は左右にスワイプする // Profile以外の場合はスワイプしない // 参考:https://stackoverflow.com/questions/63611393/react-native-material-top-tab-navigator-swipe-disable-depending-on-screens const focusCheck = ({navigation, route}) => ({ focus: () => { console.log('focus: ', route.name); setSwipeEnabled(route.name === 'Profile'); }, });
3.メイン画面に組み込む
// メイン const App = () => { return ( <> <NavigationContainer> <TopTabsScreen /> </NavigationContainer> <StatusBar barStyle="dark-content" /> </> ); };
おまけ
独自タブバー
標準でスタイルが適用されているが、一部独自に組み込みたい場合
import React from 'react'; import {View, Text, TouchableOpacity} from 'react-native'; import Animated from 'react-native-reanimated'; // 独自タブ // 参考:https://bagelee.com/programming/react-native/react-navigation-customize/ // 参考:https://reactnavigation.org/docs/material-top-tab-navigator const AppTabBar = ({state, descriptors, navigation, position}) => { const {routes, index} = state; const { containerStyle, tabStyle, selectedTabStyle, textStyle, selectedTextStyle, } = styles; //console.log(position); //console.log(descriptors); return ( <View style={containerStyle}> {routes.map((route, idx) => { //const inputRange = state.routes.map((_, i) => i); //console.log(inputRange); // 選択しているタブ if (index === idx) { return ( <View key={idx} style={[tabStyle, selectedTabStyle]}> <Text style={[textStyle, selectedTextStyle]}> {routes[idx].name} </Text> </View> ); } // 他のタブ return ( <TouchableOpacity style={tabStyle} key={idx} onPress={() => { // タップしたら他のタブへ切り替え navigation.navigate(route.name); }}> <Animated.Text style={[textStyle]}> {routes[idx].name} </Animated.Text> </TouchableOpacity> ); })} </View> ); }; const styles = { containerStyle: { //paddingTop: 30, borderBottomWidth: 3, borderBottomColor: '#5ab4bd', display: 'flex', flexDirection: 'row', justifyContent: 'space-between', backgroundColor: '#fcf6d6', }, tabStyle: { flex: 1, //marginRight: 1, //marginLeft: 1, height: 40, //borderTopLeftRadius: 16, //borderTopRightRadius: 16, backgroundColor: '#ffffff', }, selectedTabStyle: { backgroundColor: '#5ab4bd', }, textStyle: { fontWeight: 'bold', textAlign: 'center', paddingTop: 14, }, selectedTextStyle: { color: '#ffffff', }, }; export default AppTabBar;
とりあえず、ここまでにしておく・・・