React Navigation V5
Installation
- 安裝
npm install @react-navigation/native
- 安裝依賴:
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
- 更新一下 Cocoapods
npx pod-install ios
- 在rn項目的最起始入口處加一句
import 'react-native-gesture-handler';
example:
import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
export default function App() {
return (
<NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
);
}
Hello React Navigation
- 安裝|Installing the stack navigator library.
npm install @react-navigation/stack
- 使用
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
// code
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
createStackNavigator 是一個方法,返回一個對象,這個對象有兩個屬性:Screen、Navigator,他們都是用來配置路由的react 組建,Navigator 應該包含Screen的elements來配置路由 NavigationContainer 是用來管理導航樹和導航狀態的容器組建,該組件必須封裝所有導航器結構
example
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Overview' }}/>
// 這裏的DetailsScreen 頁面 沒有寫
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
initialRouteName 初始化起始頁面
頁面跳轉
// 跳轉到某個頁面,如Setting頁面,不過跳轉多少次,僅會打開一次這個頁面,
// 如果在當前頁面跳轉,沒有效果
this.props.navigation.navigate('Setting')
// 跳轉到某個頁面,如Setting頁面,跳轉多次會打開多個Setting頁面,
// 在Setting頁面跳轉會再次打開這個頁面
this.props.navigation. push('Setting')
// 返回上一個頁面
navigation.goBack()
// 返回到某一個頁面,如Home頁面,注意不要用push
navigate('Home')
// 返回到第一個頁面
navigation.popToTop()
跳轉參數處理
// 傳參
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
// 取參
const { itemId, otherParam } = route.params;
// 更新參數
navigation.setParams({
query: 'someText',
})
// 初始化默認頁面參數
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 42 }}
/>
向前一個頁面傳遞參數
// home->detail->home
// 通過navigate 把參數傳遞回去
navigation.navigate({
name: 'Home',
params: { post: postText },
merge: true,
});
導航欄配置
- 設置導航欄標題
// options 中的titlte
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'My home' }}
/>
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={({ route }) => ({ title: route.params.name })}
/>
</Stack.Navigator>
// navigation.setOptions 設置title
this.props.navigation.setOptions({ title: 'Updated!' })
- 導航欄樣式
- headerStyle 導航欄樣式
- headerTintColor 導航欄標題顏色
- headerTitleStyle 導航欄標題樣式
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: 'My home',
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}
/>
</Stack.Navigator>
- screenOptions 配置公共導航欄樣式
- headerStyle、headerTitleStyle、headerTintColor 同上
<NavigationContainer>
<Stack.Navigator
initialRouteName={'Home'}
screenOptions={{
headerStyle: {
backgroundColor: '#00FF00',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}>
<Stack.Screen name="Home" component={HomePage} options={{
title: 'My home',
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}} />
<Stack.Screen name="Setting" component={SettingPage} options={{ title: 'Overview' }}/>
</Stack.Navigator>
</NavigationContainer>
- 用自定義組件替換標題
headerTitle 接受一個組件,替換導航欄標題
function LogoTitle() {
return (
<Image
style={{ width: 50, height: 50 }}
source={require('@expo/snack-static/react-native-logo.png')}
/>
);
}
function StackScreen() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ headerTitle: props => <LogoTitle {...props} /> }}
/>
</Stack.Navigator>
);
}
導航欄按鈕
// headerRight 接受一個方法,方法返回組件,可以用來在右邊放按鈕、或者其他的...
// 注意headerRight 接受的方法中的this並不指向組件的this
<Stack.Screen
name="Setting"
component={SettingPage}
options={{
headerTitle: null,
headerRight:() => (
<View
style={{
width:30,
height:30,
marginRight:15,
backgroundColor:'green'
}}
/>
)
}}
/>
// 可以在組件中使用setOptions,從而指向this,也可以使用hook...(更多的可以動動腦,或者查閱相關資料)
componentDidMount() {
this.props.navigation.setOptions({
headerRight: this._getRightBtn,
})
}
_getRightBtn=()=>{
return (
<Button onPress={() => {
this.setState({
count:5
})
}} title="Update count11" />
)
}
- headerBackTitle 自定義返回按鈕的文案
- headerBackImage 自定義返回按鈕的圖片
- headerLeft 自定義返回按鈕 ,參考headerRight
- headerTitle 自定義標題部分的視圖
Nesting navigators 嵌套導航欄
function Home() {
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="Messages" component={Messages} />
</Tab.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
</NavigationContainer>
);
}
路由嵌套如下
- Stack.Navigator
- Home (Tab.Navigator)
- Feed (Screen)
- Messages (Screen)
- Profile (Screen)
- Settings (Screen)
- Home (Tab.Navigator)
嵌套路由的跳轉
navigation.navigate('Root', {
screen: 'Settings',
params: {
screen: 'Sound',
params: {
screen: 'Media',
},
},
});
headerShown 在嵌套路由器中,會存在部分頁面導航欄需要隱藏,是有這個headerShown:false來隱藏導航欄