菜鸟一枚,入手rn不久,发现react-navigation中文文档都挺旧的,很多无法参考,所以想把我遇到的问题分享出来,帮助后来者
我用的mac mini开发 react-native 0.63 @react-navigation/native 5.9.4 具体可以参考官方文档 不过只有英文版看的磕磕碰碰
react-navigation功能很强大 目前已经更新到6.x
5.9以前的版本很多地方使用都更变了 90%关于react-navigation教程都是5.x前版本
安装
yarn add @react-navigation/native
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
npx pod-install ios
复制代码
这三个都要安装 我第一次就是没安装全 找了好久原因
React Native 0.60及以上版本是自动链接库的,不需要手动运行react-native link,但如果你用React Native开发的是iOS,还需要手动安装pods来完成库的链接:
npx pod-install ios
复制代码
如果你需要手势库 可以在入口文件index.js或者app.js 顶部添加 import ‘react-native-gesture-handler’
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>
);
}
复制代码
如果你使用了Redux框架,需要把Provider放在最外层,将NavigationContainer包裹在次外层,类似下面这样:
export default class App() {
return (
<Provider store={store}>
<NavigationContainer>
{/* Screen configuration */}
</NavigationContainer>
</Provider>
);
}
复制代码
导航分类
- StackNavigator栈导航 可以理解成头部导航栏
- TabNavigator标签导航 可以理解成底部导航栏
- DrawerNavigator抽屉导航 可以理解成左右滑出弹窗
因为我只用到StackNavigator 所以主要讲StackNavigator 其他两者使用大同小异
yarn add @react-navigation/stack
复制代码
// 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 { createStackNavigator } from '@react-navigation/stack';
function HomeScreen (props) {
return <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}><Button
title="Go to Login... again"
onPress={() => props.navigation.navigate('Login')}
/></View>
}
function LoginScreen () {
return <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}><Text>Home</Text></View>
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" >
{props => <HomeScreen {...props} />}
</Stack.Screen>
<Stack.Screen name="Login" component={LoginScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
复制代码
会默认选择第一个Stack.Screen页面为首页
可配置太多了 只会挑重点和常用来讲
以下是他的一些常用参数配置
Stack.Navigator的配置选项
<Stack.Navigator
initialRouteName="Home"//初始页面
screenOptions={{
title: '测试标题',//初始页面标题
headerStyle: {
backgroundColor: 'green'//导航栏背景颜色
},
headerTintColor: '#fff',//导航栏字体颜色
headerTitleStyle: {
fontWeight: 'bold',
fontSize: 20
}
}}
keyboardHandlingEnabled={true} //如果为false,则导航到新屏幕时,屏幕键盘不会自动关闭。默认为true
mode="card"
/*
定义渲染和过渡的样式
card:使用标准的iOS和Android屏幕过渡。这是默认值.
modal:这有两件事:设置headerMode到screen堆栈,除非指定使屏幕从iOS底部的底部滑入,这是一种常见的iOS模式.
*/
headerMode="none"
/*
指定标题的呈现方式
float:渲染停留在顶部的单个标题,并在更改屏幕时进行动画处理。iOS上的常见模式。
screen:每个屏幕都有一个附加的标题,标题随屏幕一起淡入和淡出。Android上的常见模式。
none :没有标题。
*/
>
复制代码
Stack.Screen的配置选项
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ //配置导航器内的各个屏幕
title: 'My Login', //名称
headerShown: true,//是否显示名称
headerTitle: <View><Text>自定义标题组件</Text></View>,//自定义导航栏名称内容
headerTitleAlign: "left",//对齐标题。可选择left或center。默认为iOS-center和Android-left
headerTitleAllowFontScaling: false,//标头标题字体是否应缩放以符合“文本大小”辅助功能设置。默认为false
headerBackAllowFontScaling: false,//后退按钮标题字体是否应缩放以符合“文本大小”辅助功能设置。默认为false。
//headerBackImage: <Image source={require('xx.png')}></Image>,//在标题的后退按钮中显示自定义图像
headerBackTitle: "自定义后退按钮文字",//iOS上的后退按钮使用的标题字符串。默认为上一个场景的headerTitle。
headerBackTitleVisible: true,//为后退按钮标题是否可见提供了一个合理的默认值,但是如果您想覆盖它,则可以使用true或false在此选项中使用
headerRight: () => (<View><Text>标题右侧自定义内容</Text></View>),
//headerLeft: () => (<View><Text>标题左侧自定义内容</Text></View>),
headerTitleStyle: { backgroundColor: 'orange', color: '#fff' },//标题的样式对象
// headerTitleStyle
// headerBackTitleStyle
// headerLeftContainerStyle
// headerRightContainerStyle
}}
/>
复制代码
以上看着很实用但实际中很难满足UI设计 可能我太菜了我项目中顶部导航没用官方的自己写的 因为UI导航样式太多了
跳转动画
还可以配置页面跳转动画 提供的方法太多自行查找
const config = {
animation: 'spring',
config: {
stiffness: 1000,
damping: 500,
mass: 3,
overshootClamping: true,
restDisplacementThreshold: 0.01,
restSpeedThreshold: 0.01,
},
};
<Stack.Screen
name="Profile"
component={Profile}
options={{
transitionSpec: {
open: config,
close: config,
},
}}
/>
//forHorizontalIOS 标准的 ios 风格从右侧滑入
//forVerticalIOS 标准的 ios 风格从底部滑入
//forModalPresentationIOS iOS 13标准 iOS 风格的模态动画
//forFadeFromBottomAndroid 标准的 Android 风格淡入底部的
//forRevealFromBottomAndroid 标准 Android 风格的 Android 底部展示
import { CardStyleInterpolators } from '@react-navigation/stack';
<Stack.Screen
name="Profile"
component={Profile}
options={{
title: 'Profile',
cardStyleInterpolator: CardStyleInterpolators.forFadeFromBottomAndroid,
}}
/>;
复制代码
导航跳转方式(重点)
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>This is the home screen!</Text>
<Button
onPress={() => navigation.navigate('Login')}
title="Open Modal"
/>
</View>
);
}
this.props.navigation.navigate("Login",{id:xxxx})
this.props.navigation.push("Login",{id:xxxx})
this.props.navigation.replace("Login",{id:xxxx})
this.props.navigation.goBack()
this.props.navigation.goBack("Login")
this.props.navigation.pop()
this.props.navigation.pop(n) //n代表返回第几层页面
this.props.navigation.popToTop()
const id=this.props.route.params.id
复制代码
- navigate 入栈新页面
- push 入栈新页面
- replace 替换当前页面(待支付到支付完成页面 后退不需要到待支付就可以用这个)
- goBack 后退一页 关闭当前页
- pop 默认返回到上一页
- popToTop 返回至最顶层页面
navigate、push 、replace区别具体看下面
如上图,外部是一个栈容器,此时A页面在最底部,navigate到B页面,为什么此时用navigate没有用push呢,因为在栈内没有B页面时,用navigate和push是一样的,都是进行入栈操作,没有区别,出于习惯使用navigate。下一步,B页面push了一个B页面,此时为何不使用navigate呢,因为栈内若已经存在一个相同页面,navigate就会失去跳转页面的效果,B navigate B代码不会报错,但是也不会进行跳转,因为栈内已经有了B,只有使用push才会进行新的B页面进行入栈操作。现在了解了navigate与push的区别,看上图,进行了一系列入栈操作,形成最终的栈图,下面分三种情况讨论。
1.现在我们处于C页面,若C push A,同样会执行A的继续入栈,但此时若使用C navigate A,则A以上全部页面会执行出栈操作,相当于popToTop方法,回到A页面;
2.现在处于C页面,若C push B,同样会执行B的继续入栈,但此时若使用C navigate B,则会当前的C开始向下寻找B界面,直到找到最近的B界面,进行跳转,C与B中间的页面全部出栈,此时B还可以继续进行返回,一步步返回至A页面;
3.还有一种与图无关的情况,A navigate BrowserPage,此时app接收到一个推送,点击推送进入了新的BrowserPage,若收到推送后跳转页面的逻辑使用的是navigate方法,此时就会出现无法跳转的情况,因为BrowserPage已经在栈内存在(刚刚在浏览网页),所以此处要使用push方法进行入栈操作;
4.A页面navigate B页面,A收到通知要navigate到C界面,此时C入栈并覆盖了B,此时点击返回是回到B界面,因为C执行出栈操作后到了B,而不会直接回到A;
5.replace方法,
replace – replace the current route with a new one
据官方文档介绍,是用一个新的路由替换掉当前的路由,即使用新的页面替换当前的页面,假设有这样的场景,A navigate到B,B完成任务后要到C,C返回的不是B,而是A,此时使用B replace C即可实现需求。
以上来自www.cnblogs.com/li-wei203/p… 我觉得讲的挺好的就引过来了
监听导航(重点)
这个用的几率挺大的 滑动后退重定向路由 或者 滑动后退离开页面阻拦提示
1.focus – 当屏幕成为焦点时,会发出这个事件
2.blur – 当屏幕失焦时会发出这个事件
3.beforeRemove (version 5.7+ only) – (版本5.7以上)-当用户离开屏幕时, 防止用户离开
4.state (advanced) – (高级)-当导航器的状态改变时发出此事件
5.tabPress (advanced) – 监听tab页切换
const unsubscribe = navigation.addListener('tabPress', e => {
// Prevent default action
e.preventDefault();
});
function Profile({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// do something
});
return unsubscribe;
}, [navigation]);
return <ProfileContent />;
}
或者
<Tab.Screen
name="Chat"
component={Chat}
listeners={({ navigation, route }) => ({
tabPress: e => {
// Prevent default action
e.preventDefault();
// Do something with the `navigation` object
navigation.navigate('AnotherPlace');
},
})}
/>
复制代码
还有一个方法 阻止屏幕后退设备上的后退按钮事件,可以调用你自己的函数来处理后退行为。此 API 仅能在 Android 上使用。
import React, { Component } from "react";
import { Text, View, StyleSheet, BackHandler, Alert } from "react-native";
class App extends Component {
backAction = () => {
Alert.alert("Hold on!", "Are you sure you want to go back?", [
{
text: "Cancel",
onPress: () => null,
style: "cancel"
},
{ text: "YES", onPress: () => BackHandler.exitApp() }
]);
return true;
};
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.backAction);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.backAction);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.text}>Click Back button!</Text>
</View>
);
}
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
},
text: {
fontSize: 18,
fontWeight: "bold"
}
});
export default App;
});
复制代码
第一次写这么长的文章 我也不知我写了啥 感觉写繁杂了 但是react-navigation的内容真的很多很多。。。感觉rn都没人写了都在推flutter(学不动了) 还有那些人在用啊