目录
react-native项目初始化
安装react-native项目
react-navigation路由库安装
基本栈路由createNativeStackNavigator
使用路由库
路由跳转与路由传参
设置路由标题
路由样式属性
自定义标题组件
标题按钮
标签路由createBottomTabNavigator
包
示例
标签路由图标和样式
react-native项目初始化
打开cmd,cd到在要进行rn项目建立的文件夹。
npx react-native init testRN
这里我的项目名设置为testRN,可以自行设定。
安装react-native项目
连接安卓虚拟机或者usb调试真机,cd进创建好的项目根目录,yarn android安装并启动。
yarn android
初次安装完毕之后,手机未断连的情况的话,后续只需虚拟机或者手机进入项目app,然后pc在项目根目录yarn start启动就可以了不用再次安装,断连之后可能得重新安装。
yarn start
启动好了之后在cmd界面按r可以更新。
react-navigation路由库安装
内容建立在android端测试,我没有测试ios。
一口气安装下列包。
yarn add @react-navigation/native react-native-screens react-native-safe-area-context @react-navigation/native-stack
对安卓进行额外配置,在testRN\android\app\src\main\java\com\testrn修改MainActivity.java文件。
代码:
import android.os.Bundle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(null); }
基本栈路由createNativeStackNavigator
使用路由库
修改app.js为以下代码
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为路由的容器,将相关内容都放在他中间 <NavigationContainer> <Stack.Navigator> {/* Stack.Screen为路由的窗口,name设置窗口名,用于跳转,窗口的组件内容放在component */} <Stack.Screen name="Home" component={HomeScreen} /> </Stack.Navigator> </NavigationContainer> ); } export default App;
路由跳转与路由传参
import * as React from 'react'; // 添加Button import { Button, View, Text } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; // 添加navigation参数 function HomeScreen({navigation}) { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> {/* 添加跳转按钮 */} <Button title="Go to Details" // navigation.navigate('Details')用于跳转,其中的Details指向对应的窗口name onPress={() => navigation.navigate('Details')} /> </View> ); } function DetailsScreen() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> </View> ); } const Stack = createNativeStackNavigator(); function App() { return ( // NavigationContainer为路由的容器,将相关内容都放在他中间 <NavigationContainer> <Stack.Navigator> {/* Stack.Screen为路由的窗口,name设置窗口名,用于跳转,窗口的组件内容放在component */} <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="Details" component={DetailsScreen} /> </Stack.Navigator> </NavigationContainer> ); } export default App;
设置路由标题
- 窗口默认会使用name作为标题名,当然也可以自行设定。我们用my home代替Home作为导航标题。
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'my home'}} />
通常一级页面跳转去二级页面时,也许会根据内容不同展示不同的标题,这时候有就需要动态配置title。
<Stack.Screen name="Details" component={DetailsScreen} options={({ route }) => ({ title: route.params.title })} />
然后只要在一级页面跳转时传递title就可以了
<Button title="Go to Details" // navigation.navigate('Details')用于跳转,其中的Details指向对应的窗口name onPress={() => navigation.navigate('Details', { title: '二级页面' })} />
<Button title="Go to Details" // navigation.navigate('Details')用于跳转,其中的Details指向对应的窗口name onPress={() => navigation.navigate('Details', { title: '二级页面' })} />
注意这里如果一级页面没有传递title,最好传递一个空对象或者在二级窗口上设置初始值否则会报错。
还可以手动更新title,使用navigation.setOptions(),其修改的是screen上的options中的属性。
<Button title="Update the title" onPress={() => navigation.setOptions({ title: 'Updated!' })} />
路由样式属性
标题居中,可以在Navigator上设置screenOptions的headerTitleAlign属性,
headerStyle:路由上方那一块的样式。
headerTintColor:修改标题字体颜色,也可以在headerTitleStyle修改color,是一个效果。
headerTitleStyle:标题字体样式。
<Stack.Navigator screenOptions={{ headerStyle: { backgroundColor: '#f4511e', }, headerTintColor: '#fff', headerTitleStyle: { fontWeight: 'bold', }, headerTitleAlign: 'center', }}> </Stack.Navigator>
自定义标题组件
设置headerTitle回调返回一个函数式组件,组件内自定义,可以是图片。
function LogoTitle() { return ( <Image style={{ width: 50, height: 50 }} source={require('./src/img/details.png')} /> ); } <Stack.Screen name="Home" component={HomeScreen} options={{ title: 'My home', headerTitle: (props) => <LogoTitle {...props} /> }} />
标题按钮
一样是在screen的options上,存在headerRight可以放按钮。
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'My home', headerTitle: (props) => <LogoTitle {...props} />, headerRight: () => ( <Button onPress={() => alert('This is a button!')} title="Info" color="#fff" /> ), }} />
headerBackImageSource可以修改回退按钮图片。
<Stack.Screen name="Details" component={DetailsScreen} options={({ route }) => ( { title: route.params.title, headerBackImageSource: detailsImg, } )} />
标签路由createBottomTabNavigator
包
yarn add @react-navigation/bottom-tabs
示例
- Tab创建标签修改为createBottomTabNavigator,基本栈路由是createNativeStackNavigator。
- 用法类似,NavigationContainer包裹,Tab.Navigator路由,Tab.Screen路由页面。
import * as React from 'react'; import {Button, View, Text, TextInput, Image} from 'react-native'; import {NavigationContainer} from '@react-navigation/native'; import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'; function HomeScreen() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Home!</Text> </View> ); } function SettingsScreen() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Settings!</Text> </View> ); } const Tab = createBottomTabNavigator(); function App() { return ( // NavigationContainer为路由的容器,将相关内容都放在他中间 <NavigationContainer> <Tab.Navigator> <Tab.Screen name="Home" component={HomeScreen} /> <Tab.Screen name="Settings" component={SettingsScreen} /> </Tab.Navigator> </NavigationContainer> ); } export default App;
标签路由图标和样式
- route.name判断是哪个路由,focused判断该路由是否选中,两个结合判断可以将标签选中未选中的图标都给定义了。
- tabBarActiveTintColor修改标签路由文字选中颜色,tabBarInactiveTintColor未选中颜色。
//导入两个路由标签选中与未选中的图标共四张图 import home from './src/img/home.png'; import homeSelect from './src/img/homeSelect.png'; import settings from './src/img/settings.png'; import settingsSelect from './src/img/settingsSelect.png';
<NavigationContainer> <Tab.Navigator screenOptions={({route}) => ({ tabBarIcon: ({focused, color, size}) => { let icon; if (route.name === 'Home') { icon = focused ? homeSelect : home; } else if (route.name === 'Settings') { icon = focused ? settingsSelect : settings; } // You can return any component that you like here! return <Image source={icon} style={{width: 20, height: 20}} />; }, tabBarActiveTintColor: 'lightblue', tabBarInactiveTintColor: 'black', })}> <Tab.Screen name="Home" component={HomeScreen} /> <Tab.Screen name="Settings" component={SettingsScreen} /> </Tab.Navigator> </NavigationContainer>