React Navigation 基本使用
参考资料
https://reactnavigation.org/docs/
环境搭建
Minimum requirementsreact-native
>= 0.63.0
expo
>= 41 (if you use Expo)typescript
>= 4.1.0 (if you use TypeScript)
Installation
npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context
From React Native 0.60 and higher, linking is automatic. So you don’t need to run react-native link
.
If you’re on a Mac and developing for iOS, you need to install the pods (via Cocoapods) to complete the linking.
npx pod-install ios
react-native-screens
package requires one additional configuration step to properly work on Android devices. Edit MainActivity.java
file which is located in android/app/src/main/java/<your package name>/MainActivity.java
.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
}
and make sure to add an import statement at the top of this file:
import android.os.Bundle;
Hello React Navigation
React Navigation提供了不同于浏览器的a标签的方案,它提供了适用了IOS和Android合适的过渡动画。
安装原生栈导航库(Installing the native stack navigator library)
到目前为止我们已经安装的库仅仅构建了Navigation的基本快,然而每个Navigation都是有一个自己的库的,为了使用原声的导航栈,我们需要安装@react-navigation/native-stac
npm install @react-navigation/native-stack
@react-navigation/native-stack
depends on react-native-screens
and the other libraries that we installed in Getting started. If you haven’t installed those yet, head over to that page and follow the installation instructions.
创建一个原生栈导航(Creating a native stack navigator)
createNativeStackNavigator
函数会返回一个包含两个属性Screen
和Navigator
的对象。他们都是用于配置配置navigator的React组件,Navigator
应该包含Screen
元素作为他们的子元素来为路由定义配置。
NavigationContainer
是一个用来管理导航树(navigation tree)的组件并且它包含了 navigation state,这个组件必须包含所有导航的结构,通常的,我们在app的根去渲染这个组件,通常这个组件被App.js被导出。(export)
// In App.js in a new project
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} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
基本案例
// 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', {
itemId: 86,
otherParam: 'anything you want here'
})
}}
/>
</View>
);
}
function DetailsScreen({route,navigation}) {
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 back" onPress={() => navigation.goBack()} />
<Button
title="Go back to first screen in stack"
onPress={() => navigation.popToTop()}
/>
</View>
);
}
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} options={{ title: '主页' }}/>
<Stack.Screen name="Details" component={DetailsScreen} options={{ title: '详情' }}/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
携返回值案例
// In App.js in a new project
import * as React from "react";
import { View, Text, Button, TextInput } 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();
function StackScreen() {
const screenOptions = {
headerStyle: {
backgroundColor: "#f4511e",
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "bold",
},
}
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: "主页", ...screenOptions }}
/>
<Stack.Screen
name="CreatePost"
component={CreatePostScreen}
options={{
title: "创建Post", ...screenOptions }}
/>
</Stack.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<StackScreen />
</NavigationContainer>
);
}
export default App;
Replacing the title with a custom component
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>
);
}
给标题来点样式
// In App.js in a new project
import * as React from "react";
import { View, Text, Button, TextInput } 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();
function StackScreen() {
const screenOptions = {
headerStyle: {
backgroundColor: "#f4511e",
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "bold",
},
}
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerTitle: () => <Text>Text</Text>,
headerRight: () => (
<Button
onPress={() => alert('This is a button!')}
title="Info"
color="black"
/>
),
}}
/>
<Stack.Screen
name="CreatePost"
component={CreatePostScreen}
options={{
headerTitle: () => <Text>Text</Text>,
headerRight: () => (
<Button
onPress={() => alert('This is a button!')}
title="Info"
color="black"
/>
),
}}
/>
</Stack.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<StackScreen />
</NavigationContainer>
);
}
export default App;
Tab.Navigator
import * as React from 'react';
import { Text, View, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons';
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<Button
title="Go to Settings"
onPress={() => navigation.navigate('Settings')}
/>
</View>
);
}
function SettingsScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
</View>
);
}
export default function App() {
const Tab = createBottomTabNavigator();
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? 'ios-information-circle'
: 'ios-information-circle-outline';
} else if (route.name === 'Settings') {
iconName = focused ? 'ios-list' : 'ios-list';
}
// You can return any component that you like here!
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: 'tomato',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={HomeScreen} options={{ tabBarBadge: 3 }}/>
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
隐藏顶部导航栏的一些办法
可以设置headerShown: false
<NavigationContainer>
<Stack.Navigator initialRouteName="Index">
<Stack.Screen
name="Index"
component={IndexScreen}
options={{ title: "主页" }, {headerShown: false}}
/>
</Stack.Navigator>
</NavigationContainer>
<Tab.Navigator>
<Tab.Screen
name="Home"
component={HomeScreen}
options={{headerShown:false}}
/>
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
Stack Navigation常用配置
<Stack.Screen
// 具体参数设定请参考:https://reactnavigation.org/docs/native-stack-navigator#options
name="Details"
component={DetailsScreen}
options={
{title: "详情"},
{animation: "slide_from_right"},// 划入方式
// {headerTitleAlign:"center"}, // 标题居中(近Android,IOS默认居中)
// {presentation: "formSheet"}, // 几乎仅IOS支持
{headerShown: true } // 不要隐藏标题,放到最后面写
}
/>
综合案例
import * as React from "react";
import { Text, View, Button, Dimensions } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import Ionicons from "react-native-vector-icons/Ionicons";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { SafeAreaView } from "react-native-safe-area-context";
// 主页
function IndexScreen({ navigation }) {
function HomeScreen() {
return (
<SafeAreaView edges={['top', 'left', 'right']}
style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}
>
<Button
title="Go to Details"
onPress={() => navigation.navigate("Details")}
/>
</SafeAreaView>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Settings!</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
Tab.navigationOptions = ({navigation}) => {
// 关键这一行设置 header:null
return{
header: null,
}
};
return (
<Tab.Navigator>
<Tab.Screen
name="Home"
component={HomeScreen}
options={{headerShown:false}}
/>
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
function DetailsScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Home Screen</Text>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
);
}
export default function App() {
const Stack = createNativeStackNavigator();
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Index">
<Stack.Screen
name="Index"
component={IndexScreen}
options={
// headerTitleAlign和 headerShown最好别混用
{title: "主页"}, {animation: "slide_from_right"},
{headerShown: false}
}
/>
<Stack.Screen
// 具体参数设定请参考:https://reactnavigation.org/docs/native-stack-navigator#options
name="Details"
component={DetailsScreen}
options={
{title: "详情"},
// {headerTitleAlign:"center"}, // 标题居中(近Android,IOS默认居中)
// {presentation: "formSheet"}, // 几乎仅IOS支持
{animation: "slide_from_right"},// 划入方式
{headerShown: true } // 不要隐藏标题
}
/>
</Stack.Navigator>
</NavigationContainer>
);
}