react-navigation使用技巧

react

 

因为react-navigation之前存在的问题相对较多,本文更新会稍慢,而且,我现在项目使用的是基于它封装的react-native-router-fluxV4版本,现在也推荐给大家使用。在下面的文章中,我提供了简易的Demo,react-native-router-flux提供了更多的API和方法教给用户使用,如果遇到不会的问题,欢迎加群讨论

react-native-router-flux使用技巧(API篇)

识兔,一款用来识别图片的开源项目,在未来还会添加更多有意思的东西

react-navigation的Demo

react-navigation使用技巧(进阶篇)

什么是react-navigation?

react-native从开源至今,一直存在几个无法解决的毛病,偶尔就会复发让人隐隐作痛,提醒你用的不是原生,其中包括列表的复用问题,导航跳转不流畅的问题等等。
终于facebook坐不住了,在前一段时间开始推荐使用react-navigation,并且在0.44发布的时将之前一直存在的Navigator废弃了。
react-navigation是致力于解决导航卡顿,数据传递,Tabbar和navigator布局,支持redux。虽然现在功能还不完善,但基本是可以在项目中推荐使用的。

属性

react-navigation分为三个部分。
StackNavigator类似顶部导航条,用来跳转页面和传递参数。
TabNavigator类似底部标签栏,用来区分模块。
DrawerNavigator抽屉,类似从App左侧滑出一个页面,在这里不做讲解。
下面会分开讲解官网提供的配置方法,但顺序可能会官网不一样。

screenProps

之前是没有介绍这个属性的,但经过这么久发现,很多人都不知道这个属性,不知道它能干嘛,在这里我就简单的介绍下

screenProps:react-navigation自带的一个属性,属于navigationOptions的一个属性,可以全局控制navigationOptions中的某些值,比如说你想做换肤功能,修改这个属性绝对是最简单的方式。

// 假设App就是项目中的入口文件,如果还不知道,可以看下Demo,在这里我将主题色通过screenProps属性修改成\'red\'

<App screenProps={{themeColor:\'red\'}}>

// 在页面中就可以通过screenProps来直接改变了,这个在Demo

中的Test2里面

static navigationOptions = ({navigation,screenProps}) => ({

// 这里面的属性和App.js的navigationOptions是一样的。

headerStyle:{backgroundColor:screenProps?

screenProps.themeColor:

\'#4ECBFC\'},

)

})

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默认支持,安卓默认关闭
  • gestureResponseDistance:对象覆盖触摸从屏幕边缘开始的距离,以识别手势。 它需要以下属性:

    • horizontal - number - 水平方向的距离 默认为25。
    • vertical - number - 垂直方向的距离 默认为135。

// 设置滑动返回的距离

gestureResponseDistance:{horizontal:300},

注:beta13新出的东西,挺有意思,以后可以手动控制返回了

导航视觉效果

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界面。

TabNavigator 基础用法/属性介绍

const MyTab = TabNavigator({

ShiTu: {

screen: ShiTu,

navigationOptions:{

tabBarLabel: \'识兔\',

tabBarIcon: ({tintColor}) => (

<Image

source={{uri : \'识兔\'}}

style={[tabBarIcon, {tintColor: tintColor}]}

/>

),

},

}, {

tabBarPosition: \'bottom\',

swipeEnabled:false,

animationEnabled:false,

tabBarOptions: {

style: {

height:49

},

activeBackgroundColor:\'white\',

activeTintColor:\'#4ECBFC\',

inactiveBackgroundColor:\'white\',

inactiveTintColor:\'#aaa\',

showLabel:false,

}

});

屏幕导航配置

screen:和导航的功能是一样的,对应界面名称,可以在其他页面通过这个screen传值和跳转。
navigationOptions:配置TabNavigator的一些属性

  • title:标题,会同时设置导航条和标签栏的title,还是不推荐这种方式。
  • tabBarVisible:是否隐藏标签栏。默认不隐藏(true)
  • tabBarIcon:设置标签栏的图标。需要给每个都设置。
  • tabBarLabel:设置标签栏的title。推荐这个方式。
  • tabBarOnPress:设置tabBar的点击事件,内部提供了两个属性,一个方法(obj)。
    beta13新添加的方法,使用方式有些奇葩,如果想要使用,请参照下面的代码

tabBarOnPress:(obj)=>{

console.log(obj);

obj.jumpToIndex(obj.scene.index)

},

标签栏配置

tabBarPosition:设置tabbar的位置,iOS默认在底部,安卓默认在顶部。(属性值:\'top\',\'bottom\')
swipeEnabled:是否允许在标签之间进行滑动。
animationEnabled:是否在更改标签时显示动画。
lazy:是否根据需要懒惰呈现标签,而不是提前制作,意思是在app打开的时候将底部标签栏全部加载,默认false,推荐改成true哦。
initialRouteName: 设置默认的页面组件
backBehavior:按 back 键是否跳转到第一个Tab(首页), none 为不跳转

tabBarOptions:配置标签栏的一些属性

iOS属性

  • activeTintColor:label和icon的前景色 活跃状态下(选中)。
  • activeBackgroundColor:label和icon的背景色 活跃状态下(选中) 。
  • inactiveTintColor:label和icon的前景色 不活跃状态下(未选中)。
  • inactiveBackgroundColor:label和icon的背景色 不活跃状态下(未选中)。
  • showLabel:是否显示label,默认开启。
  • style:tabbar的样式。
  • labelStyle:label的样式。

安卓属性

  • activeTintColor:label和icon的前景色 活跃状态下(选中) 。
  • inactiveTintColor:label和icon的前景色 不活跃状态下(未选中)。
  • showIcon:是否显示图标,默认关闭。
  • showLabel:是否显示label,默认开启。
  • style:tabbar的样式。
  • labelStyle:label的样式。
  • upperCaseLabel:是否使标签大写,默认为true。
  • pressColor:material涟漪效果的颜色(安卓版本需要大于5.0)。
  • pressOpacity:按压标签的透明度变化(安卓版本需要小于5.0)。
  • scrollEnabled:是否启用可滚动选项卡。
  • tabStyle:tab的样式。
  • indicatorStyle:标签指示器的样式对象(选项卡底部的行)。安卓底部会多出一条线,可以将height设置为0来暂时解决这个问题。
  • labelStyle:label的样式。
  • iconStyle:图标的样式。
    ps:很多人问我,为什么安卓上的tabbar文字会下移, 是因为安卓比iOS多了一个属性,就是iconStyle,通过设置labelStyleiconStyle两个样式,外加style的高度,来使效果更佳合理.

跳转

navigate(\'Detail\',{

title:\'图片详情\',

url:item.url,

});

Detail:在StackNavigator中注册的页面,需要一一对应,才能跳转到相应的页面
title:在跳转的页面可以通过this.props.navigation.state.params.title获取到这个参数。当然这个参数可以随便填写,都可以通过this.props.navigation.state.params.xxx获取。

回调传参

navigate(\'Detail\',{

// 跳转的时候携带一个参数去下个页面

callback: (data)=>{

console.log(data); // 打印值为:\'回调参数\'

}

});

const {navigate,goBack,state} = this.props.navigation;

// 在第二个页面,在goBack之前,将上个页面的方法取到,并回传参数,这样回传的参数会重走render方法

state.params.callback(\'回调参数\');

goBack();

自定义

项目中基本是没可能用自带的那个导航条的,自带导航条左侧的按钮永远是蓝色的,如果我们需要更改按钮颜色,就需要用到自定义的功能了。

const StackOptions = ({navigation}) => {

console.log(navigation);

let {state,goBack} = navigation;

// 用来判断是否隐藏或显示header

const visible= state.params.isVisible;

let header;

if (visible === true){

header = null;

}

const headerStyle = {backgroundColor:\'#4ECBFC\'};

const headerTitle = state.params.title;

const headerTitleStyle = {fontSize:FONT_SIZE(20),color:\'white\',fontWeight:\'500\'}

const headerBackTitle = false;

const headerLeft = (

<Button

isCustom={true}

customView={

<Icon

name=\'ios-arrow-back\'

size={30}

color=\'white\'

style={{marginLeft:13}}

/>

}

onPress={()=>{goBack()}}

/>

);

return {headerStyle,headerTitle,headerTitleStyle,headerBackTitle,headerLeft,header}

};

然后通过下面的方法调用就可以自定制导航了。

const MyApp = StackNavigator({

MyTab: {

screen: MyTab,

},

Detail: {

screen: Detail,

navigationOptions: ({navigation}) => StackOptions({navigation})

},

)};

在页面中使用的时候,在跳转页面的时候需要传递title参数,才能看到效果哦。

自定义tabbar

早上有人问我,tabbar的图标可不可以使用原图,选中状态下可不可以设置其他图标。研究了一下官方文档,发现tabBarIcon除了tintColor还有另一个属性,用来判断选中状态的focused

 tabBarIcon: ({tintColor,focused}) => (

focused

?

<Image

source={{uri : \'识兔\'}}

style={tabBarIcon}

/>

:

<Image

source={{uri : \'干货\'}}

style={[tabBarIcon, {tintColor: tintColor}]}

/>

),

通过判断focused,选中状态下使用识兔图标,未选中状态使用干货图标。
如果想使用图标原来的样子,那就将styletintColor去掉,这样就会显示图标原本的颜色。

再封装

export const TabOptions = (tabBarTitle,normalImage,selectedImage,navTitle) => {

// console.log(navigation);

const tabBarLabel = tabBarTitle;

console.log(navTitle);

const tabBarIcon = (({tintColor,focused})=> {

return(

focused

?

<Image

source={{uri : normalImage}}

style={[TabBarIcon, {tintColor: tintColor}]}

/>

:

<Image

source={{uri : selectedImage}}

style={[TabBarIcon, {tintColor: tintColor}]}

/>

)

});

const headerTitle = navTitle;

const headerTitleStyle = {fontSize:FONT_SIZE(20),color:\'white\'};

// header的style

const headerStyle = {backgroundColor:\'#4ECBFC\'};

return {tabBarLabel,tabBarIcon,headerTitle,headerTitleStyle,headerStyle};

};

在static中使用this方法

我之前文章中是将navaigationOptions的方法写在了app.js中,没有在页面中通过static navaigationOptions来初始化页面,这段时间刚好有人问,所以在这里就写一下该怎么弄。

首先需要在componentDidMount(){}中动态的添加点击事件

属性给params

componentDidMount(){

this.props.navigation.setParams({

title:\'自定义Header\',

navigatePress:this.navigatePress

})

}

navigatePress = () => {

alert(\'点击headerRight\');

console.log(this.props.navigation);

}

接下来就可以通过params方法来获取点击事件了

static navigationOptions = ({ navigation, screenProps }) => ({

title: navigation.state.params?navigation.state.params.title:null,

headerRight:(

<Text onPress={navigation.state.params?navigation.state.params.navigatePress:null}>

返回

</Text>

)

});

让安卓实现push动画

之前我群里的讨论怎么让安卓实现类似iOS的push动画,后来翻看官方issues的时候,真的发现了实现push动画的代码,在这里共享下

// 先引入这个方法

import CardStackStyleInterpolator from \'react-navigation/src/views/CardStackStyleInterpolator\';

// 在StackNavigator配置headerMode的地方,使用transitionConfig添加

{

headerMode: \'screen\',

transitionConfig:()=>({

screenInterpolator:CardStackStyleInterpolator.forHorizontal,

})

}

关于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,

};

}

}

感谢群友conan的贡献,将源码改成上面的样子,就可以使用goBack()返回指定页面了,这样的优点不言而喻,但缺点就是每次调用goBack(),如果只是简单的返回上一页需要加上null参数,类似这样goBack(null)

如果这样修改,在滑动返回的时候,会有很大几率让项目卡死,请注意使用该方法,推荐集成redux。

关于快速点击会导致多次跳转的问题解决办法

感谢群友编程大叔的贡献,如果想解决快速点击跳转的问题,需要修改部分源码。

修改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"

ps:在iOS下如果想一劳永逸的解决键盘问题,请使用IQKeyBoardManager

总结

react-navigation才开始用的时候感觉是复杂的,但用的多了,会感觉真的很不错。
如果在文章中有什么不懂的问题,欢迎在评论区评论,也可以发私信,加QQ群397885169一起讨论哦

 React-Native

© 著作权归作者所有

举报文章

关注挂着铃铛的兔 

写了 29600 字,被 760 人关注,获得了 443 个喜欢

一名iOS开发程序猿,正在往前端的路上越走越远。

 

喜欢

 

163

   

  • 分享到QQ空间
  • 分享到Twitter
  • 分享到Facebook
  • 分享到Google+
  • 分享到豆瓣
  • " data-original-title="">更多分享


     

     

    被以下专题收入,发现更多相似内容

    React N...


    React N...

    React N...

    展开更多 

     

    react-navigation使用技巧(进阶篇)

    之前写过react-navigation使用技巧,那篇文章中主要讲了react-navigation的属性,封装和一些小技巧。虽然上篇文章中也有一些小技巧,但因为补充的比较晚,导致有些人没有看全,再加上我又找到了一些新的小玩意,特此写了本篇文章,如果之后还有新发现,也会再这...

     挂着铃铛的兔

    react-navigation使用详解-简书

    react-navigation导航组件使用详解 福利时间 作者React Native开源项目OneM地址(按照企业开发标准搭建框架完成开发的):https://github.com/guangqiang-liu/OneM (欢迎小伙伴们 star) 作者简书主页:包含5...

     光强_上海

     

     

     

     

     

    以上是 react-navigation使用技巧 的全部内容, 来源链接: utcz.com/z/382768.html

    回到顶部