本小节我们来看两个内容:
- 参数传递
- 标题栏信息配置
参数传递#
参数传递在导航中是一个非常重要的内容,例如点击电影进入到这一部电影的电影详情,那么我们就需要传递一个 id 过去。
参数传递整体分为两步:
- 传递参数:通过将参数放在对象中作为 navigation.navigate 函数的第二个参数,将参数传递给路由
navigation.navigate('RouteName', { /* params go here */})- 接受参数:获取上一屏组件传递过来的参数
route.params来看一个官方提供的示例:
function HomeScreen({ navigation }) { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title="Go to Details" onPress={() => { /* 1. Navigate to the Details route with params */ navigation.navigate('Details', { itemId: 86, otherParam: 'anything you want here', }) }} /> </View> )}
function DetailsScreen({ route, navigation }) { /* 2. Get the param */ const { itemId, otherParam } = route.params return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Text>itemId: {JSON.stringify(itemId)}</Text> <Text>otherParam: {JSON.stringify(otherParam)}</Text> <Button title="Go to Details... again" onPress={() => navigation.push('Details', { itemId: Math.floor(Math.random() * 100), }) } /> <Button title="Go to Home" onPress={() => navigation.navigate('Home')} /> <Button title="Go back" onPress={() => navigation.goBack()} /> </View> )}第二屏不仅可以接收第一屏传递过来的参数,还可以手动修改这个参数,例如:
<Button title="修改参数" onPress={() => { navigation.setParams({ otherParam: 'someText', }) }}/>在上面的代码中,我们在 DetailsScreen 这一屏所返回的 JSX 中,添加了一个 Button 组件,点击之后通过 navigation.setParams 重新设置接收到的 otherParam 参数。
可以在 Stack.Screen 中通过 initialParams 属性设置参数的默认值,例如:
<Stack.Screen name="Details" component={DetailsScreen} initialParams={{ itemId: 42 }}/>设置之后,我们在 Home 这一屏中,跳转到 DetailsScreen 时,即使不传递 itemId 参数,DetailsScreen 这一屏也能接收到一个名为 itemId 的参数。
有些时候,我们并不是只会将第一屏的数据传递给第二屏,可能刚好相反要将第二屏的数据反向传递给第一屏,使用 navigate 方法的时候,也可以很轻松的向上一屏传递数据。例如:
import * as React from 'react'import { Text, TextInput, View, Button } from 'react-native'import { NavigationContainer } from '@react-navigation/native'import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen({ navigation, route }) { React.useEffect(() => { if (route.params?.post) { // Post updated, do something with `route.params.post` // For example, send the post to the server } }, [route.params?.post])
return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Button title="Create post" onPress={() => navigation.navigate('CreatePost')} /> <Text style={{ margin: 10 }}>Post: {route.params?.post}</Text> </View> )}
function CreatePostScreen({ navigation, route }) { const [postText, setPostText] = React.useState('')
return ( <> <TextInput multiline placeholder="What's on your mind?" style={{ height: 200, padding: 10, backgroundColor: 'white' }} value={postText} onChangeText={setPostText} /> <Button title="Done" onPress={() => { // Pass and merge params back to home screen navigation.navigate({ name: 'Home', params: { post: postText }, merge: true, }) }} /> </> )}
const Stack = createNativeStackNavigator()
export default function App() { return ( <NavigationContainer> <Stack.Navigator mode="modal"> <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="CreatePost" component={CreatePostScreen} /> </Stack.Navigator> </NavigationContainer> )}标题栏信息配置#
Screen 组件接受 options 属性,它可以是对象,也可以是返回对象的函数,其中包含各种配置选项。 例如上面我们所写的:
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Overview' }}/>有些时候标题栏并不是一开始就固定的,而是通过上一屏跳转过来时传递的参数过来而决定的。例如:
import * as React from 'react'import { View, Text, Button } from 'react-native'import { NavigationContainer } from '@react-navigation/native'import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen({ navigation }) { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title="Go to Profile" onPress={() => navigation.navigate('Profile', { name: 'Custom profile header' }) } /> </View> )}
function ProfileScreen({ navigation }) { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Profile screen</Text> <Button title="Go back" onPress={() => navigation.goBack()} /> </View> )}
const Stack = createNativeStackNavigator()
function App() { return ( <NavigationContainer> <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> </NavigationContainer> )}
export default App在标题栏内容已经确定的当前屏幕下,想要修改当前屏的标题,可以使用 navigation.setOptions,来看下面的例子:
import * as React from 'react'import { View, Text, Button } from 'react-native'import { NavigationContainer } from '@react-navigation/native'import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen({ navigation }) { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title="Update the title" onPress={() => navigation.setOptions({ title: 'Updated!' })} /> </View> )}
const Stack = createNativeStackNavigator()
function App() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={HomeScreen} options={{ title: 'My home' }} /> </Stack.Navigator> </NavigationContainer> )}
export default App我们可以自定义标题的样式。自定义标题样式时要使用三个关键属性:headerStyle、headerTintColor 和 headerTitleStyle。
- headerStyle:一个样式对象,将应用于包装标题的 View。 如果你在它上面设置了 backgroundColor,那将是你的标题的颜色。
- headerTintColor:后退按钮和标题都使用这个属性作为它们的颜色。 在下面的示例中,我们将色调颜色设置为白色 (#fff),因此后退按钮和标题标题将为白色。
- headerTitleStyle:如果我们想自定义标题的 fontFamily、fontWeight 等 Text 样式属性,可以用这个来做。
例如:
import * as React from 'react'import { View, Text } from 'react-native'import { NavigationContainer } from '@react-navigation/native'import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> </View> )}
const Stack = createNativeStackNavigator()
function App() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={HomeScreen} options={{ title: 'My home', headerStyle: { backgroundColor: '#f4511e', }, headerTintColor: '#fff', }} /> </Stack.Navigator> </NavigationContainer> )}
export default App一个很常见的需求,就是将整个应用的标题栏样式统一成一个样式。可以通过配置 screenOptions 来实现这个功能。如下:
// In App.js in a new project
import * as React from 'react'import { View, Text, Button } from 'react-native'import { NavigationContainer } from '@react-navigation/native'import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen({ navigation }) { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title="Go to Details" onPress={() => navigation.navigate('Details')} /> </View> )}
function DetailsScreen({ navigation }) { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> </View> )}
const Stack = createNativeStackNavigator()
function App() { return ( <NavigationContainer> <Stack.Navigator screenOptions={{ headerStyle: { backgroundColor: '#f4511e', }, headerTintColor: '#fff', }} > <Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Overview' }} /> <Stack.Screen name="Details" component={DetailsScreen} /> </Stack.Navigator> </NavigationContainer> )}
export default App有时,我们需要的不仅仅是更改标题的文本和样式,还需要更多的控制。
例如,我们可能想要渲染图像来代替标题,或者将标题变成一个按钮。在这些情况下,可以完全覆盖用于标题的组件并提供我们自己的组件。例如:
import * as React from 'react'import { View, Text, Image } from 'react-native'import { NavigationContainer } from '@react-navigation/native'import { createNativeStackNavigator } from '@react-navigation/native-stack'
function HomeScreen() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> </View> )}
function LogoTitle() { return ( <Image style={{ width: 30, height: 30 }} source={require('./images/logo.jpg')} /> )}
const Stack = createNativeStackNavigator()
function App() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={HomeScreen} options={{ headerTitle: (props) => <LogoTitle {...props} /> }} /> </Stack.Navigator> </NavigationContainer> )}
export default App