前面我们学习了React Native常见的组件的属性和方法,以及简单的应用,那我们接下来学习一下常用的第三方的组件,第一个就是navigation和TabBar。
一.导入
npm install react-navigation --save
二.简介
react-navigation主要包括导航,底部tab,顶部tab,侧滑等,功能很强大,而且体验接近原生。今天我们介绍的组件分别为:
- 导航 -> StackNavigator
- 底部或者顶部tab -> TabNavigator
- 侧滑 -> DrawerNavigator
(一).StackNavigator
基础用法/属性介绍
const MyApp = StackNavigator({
// 对应界面名称
MyTab: { screen: MyTab, },
Detail: { screen: Detail, navigationOptions:{ headerTitle:'详情', headerBackTitle:null, } },
},
{ headerMode: 'screen', });
导航配置
- screen:对应界面名称,需要填入import之后的页面。
- navigationOptions:配置StackNavigator的一些属性。
- title:标题,如果设置了这个导航栏和标签栏的title就会变成一样的,所以不推荐使用这个方法。
- header:可以设置一些导航的属性,当然如果想隐藏顶部导航条只要将这个属性设置为null就可以了。
- headerTitle:设置导航栏标题,推荐用这个方法。
- headerBackTitle:设置跳转页面左侧返回箭头后面的文字,默认是上一个页面的标题。可以自定义,也可以设置为null
- headerTruncatedBackTitle:设置当上个页面标题不符合返回箭头后的文字时,默认改成"返回"。(上个页面的标题过长,导致显示不下,所以改成了短一些的。)
- headerRight:设置导航条右侧。可以是按钮或者其他。
- headerLeft:设置导航条左侧。可以是按钮或者其他。
- headerStyle:设置导航条的样式。背景色,宽高等。如果想去掉安卓导航条底部阴影可以添加elevation: 0,iOS下用shadowOpacity: 0。
- headerTitleStyle:设置导航条文字样式。安卓上如果要设置文字居中,只要添加alignSelf:'center'就可以了
- headerBackTitleStyle:设置导航条返回文字样式。
- headerTintColor:设置导航栏文字颜色。总感觉和上面重叠了。
- headerPressColorAndroid:安卓独有的设置颜色纹理,需要安卓版本大于5.0
- gesturesEnabled:是否支持滑动返回收拾,iOS默认支持,安卓默认关闭
导航视觉效果 - mode:定义跳转风格。
- card:使用iOS和安卓默认的风格。
- modal:iOS独有的使屏幕从底部画出。类似iOS的present效果
- headerMode:边缘滑动返回上级页面时动画效果。
- float:iOS默认的效果,可以看到一个明显的过渡动画。
- screen:滑动过程中,整个页面都会返回。
- none:没有动画。
- cardStyle:自定义设置跳转效果。
- transitionConfig: 自定义设置滑动返回的配置。
- onTransitionStart:当转换动画即将开始时被调用的功能。
- onTransitionEnd:当转换动画完成,将被调用的功能。
- path:路由中设置的路径的覆盖映射配置。
- initialRouteName:设置默认的页面组件,必须是上面已注册的页面组件。
- initialRouteParams:初始路由的参数。
- path:path属性适用于其他app或浏览器使用url打开本app并进入指定页面。path属性用于声明一个界面路径,例如:【/pages/Home】。此时我们可以在手机浏览器中输入:app名称://pages/Home来启动该App,并进入Home界面。
Demo
组件注册
const Navigator = StackNavigator(
{ Login: {screen: Login},
ForgotPassword: {screen: ForgotPassword, navigationOptions: {header: null,}},
CodeLogin: {screen: CodeLogin}, }, { navigationOptions: { headerStyle: {backgroundColor: color.theme}, headerBackTitle: null, headerTintColor: '#ffffff', showIcon: true, },
transitionConfig: TransitionConfiguration,
headerMode: 'screen', // 导航栏的显示模式, screen: 有渐变透明效果, float: 无透明效果, none: 隐藏导航栏 }
);
动画切换
const TransitionConfiguration = () => ({
screenInterpolator: (sceneProps) => { const {scene} = sceneProps;
const {route} = scene; const params = route.params || {};
const transition = params.transition || 'forHorizontal';
return CardStackStyleInterpolator[transition](sceneProps); },
});
Model弹出
const {navigate} = this.props.navigation;
navigate('CodeLogin', {transition: 'forVertical'});
参数传递
const {navigate} = this.props.navigation;
navigate('CodeLogin', {phone: this.state.phone});
读取参数
phone=this.props.navigation.state.params.phone,
函数传递
navigate('CodeLogin', { setPictureData: this.setPictureData.bind(this) });
函数调用
this.props.navigation.state.params.setPictureData(data.path)
重置路由切换导航控制器
this.props.navigation.dispatch(resetAction)})
切换到Main页面
const resetAction = NavigationActions.reset({ index: 0, actions: [ NavigationActions.navigate({ routeName: 'Main'}) ] })
关于goBack返回指定页面
react-navigation是提供了goBack()到指定页面的方法的,那就是在goBack()中添加一个参数,但当你使用goBack('Main')的时候,你会发现并没有跳转,原因是react-navigation默认goBack()中的参数是系统随机分配的key,而不是手动设置的routeName,而方法内部又没有提供可以获得key的方法,所以这里只能通过修改源码将key换成routeName了。
下面的内容直接引用了hello老文的内容
把项目/node_modules/react-navigation/src/routers/StackRouter.js文件里的
const backRoute = state.routes.find((route: *) => route.key === action.key);
改成 const backRoute = state.routes.find(route => route.routeName === action.key);
但不是很完美, 这里的component要填想返回的组件的前一个组件的routeName, 比如你的栈里顺序是home1, home2, home3, home4, 在home4里要返回home2, 使用this.props.navigation.goBack('home3'); 并且又会带出一个问题: goBack()方法没反应了, 必须加个null进去, 写成goBack(null)...
关于goBack返回指定页面的修改完善版
if (action.type === NavigationActions.BACK) {
let backRouteIndex = null;
if (action.key) {
const backRoute = state.routes.find(
/* $FlowFixMe */
/* 修改源码 */
route => route.routeName === action.key
/* (route: *) => route.key === action.key */
);
/* $FlowFixMe */
console.log('backRoute =====',backRoute);
backRouteIndex = state.routes.indexOf(backRoute);
console.log('backRoute =====',backRouteIndex);
}
if (backRouteIndex == null) {
return StateUtils.pop(state);
}
if (backRouteIndex >= 0) {
return {
...state,
routes: state.routes.slice(0, backRouteIndex+1),
index: backRouteIndex - 1 + 1,
};
}
}
关于快速点击会导致多次跳转的问题解决办法
修改react-navigation目录下,scr文件夹中的addNavigationHelpers.js文件,可以直接替换成下面的文本
export default function<S: *>(navigation: NavigationProp<S, NavigationAction>) {
// 添加点击判断
let debounce = true;
return {
...navigation,
goBack: (key?: ?string): boolean =>
navigation.dispatch(
NavigationActions.back({
key: key === undefined ? navigation.state.key : key,
}),
),
navigate: (routeName: string,
params?: NavigationParams,
action?: NavigationAction,): boolean => {
if (debounce) {
debounce = false;
navigation.dispatch(
NavigationActions.navigate({
routeName,
params,
action,
}),
);
setTimeout(
() => {
debounce = true;
},
500,
);
return true;
}
return false;
},
/**
* For updating current route params. For example the nav bar title and
* buttons are based on the route params.
* This means `setParams` can be used to update nav bar for example.
*/
setParams: (params: NavigationParams): boolean =>
navigation.dispatch(
NavigationActions.setParams({
params,
key: navigation.state.key,
}),
),
};
}
安卓上,使用TextInput的时候会让TabBar顶起来的解决办法
最简单的解决办法就是在android目录中,添加一句话
目录:android/app/src/main/AndroidManifest.xml中,添加
android:windowSoftInputMode="stateAlwaysHidden|adjustPan|adjustResize"