zoukankan      html  css  js  c++  java
  • React Native导航器之react-navigation使用

    在上一节Navigation组件,我们使用系统提供的导航组件做了一个跳转的例子,不过其实战能力不强,这里推荐一个超牛逼的第三方库:react-navigation。在讲react-navigation之前,我们先看一下常用的导航组件。

    导航控件

    常见的导航主要分为三种: 
    1.StackNavigator :类似于普通的Navigator,屏幕上方导航栏 
    2.TabNavigator:obviously, 相当于iOS里面的TabBarController,屏幕下方标签栏 
    3.DrawerNavigator:抽屉效果,左侧滑出这种效果。

    在你使用navigation的每一个界面navigation都提供相关的属性和响应方法,常见的有: 
    navigate 定义跳转到另一个页面 
    调用此方法去链接你的其他界面,主要有以下参数: 
    ·routeName- 目标路由名称,将在你的app router中注册 
    ·params-将参数合并到目标router中 
    ·action-(高级)sub-action ,如果该界面是一个navigator的话,将运行这个sub-action

    例如:

    class HomeScreen extends React.Component {
      render() {
        const {navigate} = this.props.navigation;
    
        return (
          <View>
            <Text>This is the home screen of the app</Text>
            <Button
              onPress={() => navigate('Profile', {name: 'Brent'})}
              title="点击我跳转"
            />
          </View>
         )
       }
    }

    state当前路由状态

    每个界面通过this.props.navigation.state去访问它的router,state其中包括了: 
    ·routeName - router配置的名称 
    ·key-用来区分router的唯一标示 
    ·params-可选的一些string参数 
    setParams-更改router中的参数 
    该方法允许界面更改router中的参数,可以用来动态的更改header的内容 
    goBack-返回,pop回上一级 
    dispatch -使用dispatch可以向任何navigation传递一些其他的action,主要支持的action有

    例如:

    import { NavigationActions } from 'react-navigation'
    
    const navigationAction = NavigationActions.navigate({
      routeName: 'Profile',
      params: {},
    
      // navigate can have a nested navigate action that will be run inside the child router
      action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
    })
    this.props.navigation.dispatch(navigationAction)

    Reset

    Reset方法会擦除掉所有的导航状态,并且使用新的结果替代。

    import { NavigationActions } from 'react-navigation'
    
    const resetAction = NavigationActions.reset({
      index: 0,
      actions: [
        NavigationActions.navigate({ routeName: 'Profile'})
      ]
    })
    this.props.navigation.dispatch(resetAction)

    SetParams

    为指定的router更新参数,该参数必须是已经存在于router的param中。

    import { NavigationActions } from 'react-navigation'
    
    const setParamsAction = NavigationActions.setParams({
      params: {}, // these are the new params that will be merged into the existing route params
      // The key of the route that should get the new params
      key: 'screen-123',
    })
    this.props.navigation.dispatch(setParamsAction)

    StackNavigator使用

    StackNavigator使用比较简单,看一个常见的例子:

    class MyHomeScreen extends React.Component {
      static navigationOptions = {
         title: 'Home',    //设置navigator的title
      }
    
      render() {
        return (
          //button的onPress方法,实现点击跳转界面,并且传递参数name:Lucy
          <Button
            onPress={() => this.props.navigation.navigate('Profile', {name: 'Lucy'})}
            title="Go to Lucy's profile"
          />
        );
      }
    }
    
    //生成路由关系
    const ModalStack = StackNavigator({
      Home: {
      //对应界面MyHomeScreen
        screen: MyHomeScreen,
      },
      Profile: {
        path: 'people/:name',
        screen: MyProfileScreen,
      },
    });

    StackNavigatorConfig

    option for the route(路由选项):

    ·initialRouteName -为stack设置默认的界面,必须和route configs里面的一个key匹配。 
    ·initialRouteParams - 初始路由的参数。 
    ·navigationOptions- 屏幕导航的默认选项。 
    ·paths-route config里面路径设置的映射。

    Visual Option(视觉选项):

    ·mode- 定义渲染(rendering)和转换(transitions)的模式,两种选项: 
    1) card-使用标准的iOS和Android的界面切换,这是默认的。 
    2)modal- 仅在iOS端有用,即模态出该视图。

    ·headerMode- 指定header应该如何被渲染,选项: 
    1)float- 共用一个header 意思就是有title文字渐变效果。 
    2)screen- 各用各的header 意思就是没有title文字渐变效果。 
    3)none- 没有header。

    ·cardStyle- 使用该属性继承或者重载一个在stack中的card的样式。 
    ·onTransitionStart- 一个函数,在换场动画开始的时候被激活。 
    ·onTransitionEnd- 一个函数,在换场动画结束的时候被激活。

    你还可以定义一个静态的navigationOptions在你的组件之上。

    lass ProfileScreen extends React.Component {
      //设置navigation选项
      static navigationOptions = {
       //标题
        title: ({ state }) => `${state.params.name}'s Profile!`,
        //头部定义了一个右按钮,来改变edit的状态 ing或者完成
        header: ({ state, setParams }) => ({
          // Render a button on the right side of the header
          // When pressed switches the screen to edit mode.
          right: (
            <Button
              title={state.params.editing ? 'Done' : 'Edit'}
              onPress={() => setParams({editing: state.params.editing ? false : true})}
            />
          ),
        }),
      };
      ...

    常用的配置中,主要有以下参数需要注意: 
    1)visible - bool值,header是否可见。 
    2)title-标题 String或者是一个react 节点 
    3)backTitle-返回按钮在iOS平台上,默认是title的值 
    4)right- react 节点显示在header右边,例如右按钮 
    5)left- react 节点显示在header左边,例如左按钮 
    6)style-header的style 
    7)titleStyle- header的title的style (^__^) 嘻嘻…… 
    8)tintColor- header的前景色 
    ·cardStack- 配置card stack

    react-navigation

    说完常见的导航器,我们在看看本文的重点:react-navigation的使用。 
    首先看一下效果: 
    这里写图片描述

    1,在项目目录下,安装React-navigation库

    npm install --save react-navigation  

    2,使用StactkNavigator来管理堆栈。暂且命名为HomeScreen.js。默认入口页面代码如下:

    import React from 'react';
    import {
      AppRegistry,
      Text,
    } from 'react-native';
    //导入stack导航组件
    import { StackNavigator } from 'react-navigation';
    
    class HomeScreen extends React.Component {
      static navigationOptions = {
        title: 'Welcome',//标题
      };
      render() {
        return <Text>Hello, Navigation!</Text>;
      }
    }
    //导航注册
    const SimpleApp = StackNavigator({
      Home: { screen: HomeScreen },
    });
    
    AppRegistry.registerComponent('SimpleApp', () => SimpleApp);

    运行效果: 
    这里写图片描述

    3,添加一个新的页面

     class ChatScreen extends React.Component {
      static navigationOptions = {
        title: 'Chat with Lucy',
      };
      render() {
        return (
          <View>
            <Text>Chat with Lucy</Text>
          </View>
        );
      }
    }

    4,在HomeScreen中添加一个button组件,使用routeName Chat关联到ChatScreen。

     class HomeScreen extends React.Component {
      static navigationOptions = {
        title: 'Welcome',
      };
      render() {
        const { navigate } = this.props.navigation;
        return (
          <View>
            <Text>Hello, Chat App!</Text>
            <Button
              onPress={() => navigate('Chat')}
              title="Chat with Lucy"
            />
          </View>
        );
      }
    }

    这段代码主要是给Button绑定onPress事件。这时候,我们使用的两个跳转的页面需要在StackNavigator进行注册:

     const SimpleApp = StackNavigator({
      Home: { screen: HomeScreen },
      Chat: { screen: ChatScreen },//新添加的页面
    });

    所以完整的代码是:

    class HomeScreen extends React.Component {  
        static navigationOptions = {  
            title: 'Welcome',//设置标题内容  
        };  
    
        render() {  
            const { navigate } = this.props.navigation;  
            return (  
                <View>  
                    <Text>Hello, Navigation!</Text>  
                    <Button  
                        onPress={() => navigate('Chat',{user:'Lucy'})}  
                        title="Chat with Lucy"/>  
                </View>  
            );  
        }  
    }  
    
    const SimpleApp = StackNavigator({  
        Home: {screen: HomeScreen},  
        Chat:{screen:ChatScreen},  
    
    });  

    参数传递

    在页面的跳转过程中,往往会伴随着参数的传递。

    1,在第一个页面定义参数,将参数传值给需要传值的页面

    constructor(props) {  
            super(props);  
            this.state = {};  
        } 
        ...
        if(navigator) {  
                navigator.push({  
                    name: 'SecondPageComponent',  
                    component: SecondPageComponent,  
                    params:{  
                        user:this.state.user,  
                        pwd:this.state.pwd  
                    }  
                })  
            }  

    2,如果需要监听页面的state状态

    onChangeText={(text) => this.setState({user: text})} 

    3,另一个页面接受参数

    componentDidMount() {  
                //这里获取从FirstPageComponent传递过来的参数: id  
                this.setState({  
                    user:this.props.user,  
                    pwd:this.props.pwd  
                });  
        }  
    

    4,去的传过来的值:

    value={this.state.user }  

    react-navigation参数传递

    对于 react-navigation参数的传递,使用上比较简单,只需要在navigate中加一个json格式的对象即可,如:

     navigate('Chat', { user: 'Lucy' })

    然后在接收的页面:

    class ChatScreen extends React.Component {
      static navigationOptions = {
        // Nav options can be defined as a function of the navigation prop:
        title: ({ state }) => `Chat with ${state.params.user}`,
      };
      render() {
        // The screen's current route is passed in to `props.navigation.state`:
        const { params } = this.props.navigation.state;
        return (
          <View>
            <Text>Chat with {params.user}</Text>
          </View>
        );
      }
    }

    所以,你就可以看到如下的效果: 
    这里写图片描述

    TabNavigator

    TabNavigator类似于底部导航效果

    // 注册tabs
    const Tabs = TabNavigator({
        Home: {
            screen: Home,
            navigationOptions: {  // 也可以写在组件的static navigationOptions内
                tabBar: {
                    label: '首页',
                    icon: ({tintColor}) => (<Image source={require('./app/images/home.png')} style={[{tintColor: tintColor},styles.icon]}/>),
                },
            }
        },
        Bill: {
            screen: Bill,
            navigationOptions: {
                tabBar: {
                    label: '账单',
                   icon: ({tintColor}) => (<Image source={require('./app/images/bill.png')} style={[{tintColor: tintColor},styles.icon]}/>),
                },
            }
        },
        Me: {
            screen: Me,
            navigationOptions: {
                tabBar: {
                    label: '我',
                    icon: ({tintColor}) => (<Image source={require('./app/images/me.png')} style={[{tintColor: tintColor},styles.icon]}/>),
                },
            }
        }
      }, {
          animationEnabled: false, // 切换页面时是否有动画效果
          tabBarPosition: 'bottom', // 显示在底端,android 默认是显示在页面顶端的
          swipeEnabled: false, // 是否可以左右滑动切换tab
          backBehavior: 'none', // 按 back 键是否跳转到第一个Tab(首页), none 为不跳转
          tabBarOptions: {
              activeTintColor: '#ff8500', // 文字和图片选中颜色
              inactiveTintColor: '#999', // 文字和图片未选中颜色
              showIcon: true, // android 默认不显示 icon, 需要设置为 true 才会显示
              indicatorStyle: {
                  height: 0  // 如TabBar下面显示有一条线,可以设高度为0后隐藏
              }, 
              style: {
                  backgroundColor: '#fff', // TabBar 背景色
                  // height: 44
              },
              labelStyle: {
                  fontSize: 10, // 文字大小
              },
          },
    });

    DrawerNavigator

    DrawerNavigator类似于抽屉侧滑效果。

    const DrawerNav = DrawerNavigator({
        Home: { screen: Home },
        Bill: { screen: Bill },
        Me: { screen: Me },
        HomeTwo: { screen: HomeTwo },
        HomeThree: { screen: HomeThree },
        HomeFour: { screen: HomeFour },
        BillTwo: { screen: BillTwo },
        BillThree: { screen: BillThree }
    }, {
        drawerWidth: 200, // 抽屉宽
        drawerPosition: 'left', // 抽屉在左边还是右边
        // contentComponent: CustomDrawerContentComponent,  // 自定义抽屉组件
        contentOptions: {
          initialRouteName: Home, // 默认页面组件
          activeTintColor: 'white',  // 选中文字颜色
          activeBackgroundColor: '#ff8500', // 选中背景颜色
          inactiveTintColor: '#666',  // 未选中文字颜色
          inactiveBackgroundColor: '#fff', // 未选中背景颜色
          style: {  // 样式
    
          }
        }
    });

    iOS版设置

    在iOS中使用react-navigation需要注意以下几点: 
    使用Xcode设置Schemes; 
    在AppDelegate添加一下代码:

    - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
      sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
      return [RCTLinkingManager application:application openURL:url
                          sourceApplication:sourceApplication annotation:annotation];
    }

    js组件在注册路由时设置唯一的路径path, 例如Home2: { screen: Home2, path:’app/Home2’ }; 
    在手机浏览器访问demo4://app/Home2, 弹窗选择打开, 就可以打开demo4 app并进到Home2页面。

    react-native-tab-navigator

    这里写图片描述

    直接上代码:

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, { Component } from 'react';
    import TabNavigator from 'react-native-tab-navigator';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      Image,
      View
    } from 'react-native';
    
    const TabNavigatorItem =TabNavigator.Item;
    //默认选项
    const TAB_HOME_NORMAL=require('./image/tabbar_homepage.png');
    const TAB_MINE_NORMAL=require('./image/tabbar_mine.png');
    //选中
    const TAB_HOME_PRESS=require('./image/tabbar_homepage_selected.png');
    const TAB_MINE_PRESS=require('./image/tabbar_mine_selected.png');
    
    export default class HelloWord extends Component {
      //默认选中
      constructor(){
        super();
        this.state={
          selectedTab:'Home',
        }
      }
      //点击方法
      onPress(tabName){
       if(tabName){
         this.setState({
             selectedTab:tabName,
           }
         );
       }
     }
    
    //渲染选项
     renderTabView(title,tabName,tabContent,isBadge){
          var tabNomal;
          var tabPress;
          switch (tabName) {
            case 'Home':
              tabNomal=TAB_HOME_NORMAL;
              tabPress=TAB_HOME_PRESS;
              break;
           case 'Mine':
            tabNomal=TAB_MINE_NORMAL;
            tabPress=TAB_MINE_PRESS;
            break;
            default:
    
          }
          return(
           <TabNavigatorItem
            selected={this.state.selectedTab===tabName}
            title={title}
            titleStyle={styles.tabText}
            selectedTitleStyle={styles.selectedTabText}
            renderIcon={()=><Image style={styles.icon} source={tabNomal}/>}
            renderSelectedIcon={()=><Image style={styles.icon} source={tabPress}/>}
    
            onPress={()=>this.onPress(tabName)}
            renderBadge={()=>isBadge?<View style={styles.badgeView}><Text style={styles.badgeText}>15</Text></View>:null}
            >
           <View style={styles.page}><Text>{tabContent}</Text></View>
           </TabNavigatorItem>
         );
       }
    
          //自定义TabView
        tabBarView(){
              return (
                <TabNavigator
                 tabBarStyle={styles.tab}
                >
                {this.renderTabView('首页','Home','首页模块',true)}
                {this.renderTabView('我的','Mine','我的模块',false)}
                </TabNavigator>
              );
            }
    
      //渲染界面
      render() {
        var tabView=this.tabBarView();
        return (
          <View style={styles.container}>
                 {tabView}
                </View>
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1
      },
      tabText: {
            fontSize: 10,
            color: 'black'
        },
        selectedTabText: {
            fontSize: 10,
            color: 'green'
        },
        tab:{
        height: 52,
        alignItems:'center',
        backgroundColor:'#f4f5f6',
       },
       tabIcon:{
        25,
        height:25,
      },
      badgeView:{
        22,
        height:14 ,
        backgroundColor:'#f85959',
        borderWidth:1,
        marginLeft:10,
        marginTop:3,
        borderColor:'#FFF',
        alignItems:'center',
        justifyContent:'center',
        borderRadius:8,
      },
      badgeText:{
        color:'#fff',
        fontSize:8,
      },
        icon: {
             22,
            height: 22
        },
        page: {
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
            backgroundColor: '#FFFFFF'
        },
    });
    
    
    AppRegistry.registerComponent('HelloWord', () => HelloWord);
    

    参考:React Native页面参数传递 
    https://reactnavigation.org/docs/intro/

    react-native-tab-navigator封装

    引用原文:http://blog.csdn.net/xiangzhihong8/article/details/71249167?ref=myread

    写博客是为了记住自己容易忘记的东西,另外也是对自己工作的总结,文章可以转载,无需版权。希望尽自己的努力,做到更好,大家一起努力进步!

    如果有什么问题,欢迎大家一起探讨,代码如有问题,欢迎各位大神指正!

  • 相关阅读:
    Ext JS学习第三天 我们所熟悉的javascript(二)
    Ext JS学习第二天 我们所熟悉的javascript(一)
    Ext JS学习第十七天 事件机制event(二)
    Ext JS学习第十六天 事件机制event(一)
    Ext JS学习第十五天 Ext基础之 Ext.DomQuery
    Ext JS学习第十四天 Ext基础之 Ext.DomHelper
    Ext JS学习第十三天 Ext基础之 Ext.Element
    Ext JS学习第十天 Ext基础之 扩展原生的javascript对象(二)
    针对错误 “服务器提交了协议冲突. Section=ResponseHeader Detail=CR 后面必须是 LF” 的原因分析
    C# 使用HttpWebRequest通过PHP接口 上传文件
  • 原文地址:https://www.cnblogs.com/summary-2017/p/7571953.html
Copyright © 2011-2022 走看看