• ReactNative: 使用导航栏组件-NavigatorIOS组件和Navigator组件


    一、简言

    在软件开发中,不论是Web还是App,它们的应用程序都是由很多的功能视图组成的。对于这些组合的视图,如何实现页面间平滑地过渡,应用都有统一的一套跳转机制,这个功能就是路由或者叫导航。应用程序通过导航,可以自由地实现页面之间的切换、前进和后退。在React中使用的是React Router,在iOS中使用的是UIKit的导航视图UINavigation和导航控制器。而在React-Native中,也提供了专门切换视图的导航栏组件NavigatorIOS和Navigator,这两个是兄弟组件,功能基本相同,区别在于封装性高低。NavigatorIOS组件的封装程度更高提供了基础的API和属性,开发者可以很方便的定制一个功能丰富的导航栏,而Navigator组件相比较而言比较简陋,它提供了足够的空间让开发者去定制,对于复杂的导航栏,它定制能力更高,而且可跨平台使用。其实,NavigatorIOS组件本质上是对UIKit的UINavigation的包装,使用NavigatorIOS组件进行页面的切换实质上就是调用了UIKit原生导航功能。本文将一一研究。

    二、navigator对象

    在组件视图进行切换的时候,navigator会作为一个属性对象被传递。我们可以通过this.props.navigator获取navigator对象。掌握navigator对象是使用NavigatorIOS组件和Navigator组件的前提基础,因为它可以控制器路由的跳转和组件的加载。navigator对象的主要API如下:

    //加载一个新的页面或者视图或者路由,并跳转到该页面
    push(route)
    
    //返回到上一个页面
    pop()
    
    //一次性返回N个页面,也即返回到指定页面,当N=1,与pop()相同
    popN(n)
    
    //替换当前的路由
    replace(route)
    
    //替换前一个页面的视图并且回退过去
    replacePrevious(route)
    
    //取代最顶层的路由并且回退回去
    resetTo(route)
    
    //回到最顶层视图
    popToTop()

    三、NavigatorIOS组件

    1、路由initialRoute默认是一个JS对象,代表一个页面或者视图,NavigatorIOS组件默认路由提供了initialRoute属性,如下所示:

    import React, { Component } from 'react';
    import {
        NavigatorIOS
    } from 'react-native';
    
    export default class NavigatorBar extends Component{
        
        render(){
            return (
                <NavigatorIOS
                    initialRoute={{
                        component: MyComponent,
                        title: "MyComponent Title",
                        passProps: {myProp:"XYQ"}    
                    }}
                />
            );
        }
    }
    
    //component :  表示当前页面需要加载的组件视图
    //title: 表示需要显示的标题
    //passProps:表示用于页面间传递数据

    2、NavigatorIOS组件属性有两大部分,分别是自身属性和持有的路由的属性,如下所示:

    自身属性:

    //导航条的背景颜色
    barTintColor
    
    //初始化路由,它是一个JavaScript对象
    initialRoute
    
    //每一页定制样式,可以设置每一个页面的背景颜色
    itemWrapperStyle
    
    //是否隐藏导航栏
    navigationBarHidden
    
    //是否隐藏阴影
    shadowHidden
    
    //导航栏上按钮的颜色设置
    tintColor
    
    //导航栏上字体的颜色
    titleTextColor
    
    //导航栏是否半透明
    translucent

    initialRoute的属性 

    //加载的视图组件
    component:function
    
    //当前视图标题
    title: string
    
    //传递的数据
    passProps: object
    
    //后退按钮图标
    backButtonIcon: Image.propTypes.source
    
    //后退按钮标题
    backButtonTitle: string
    
    //左边按钮图标
    leftButtonIcon: Image.propTypes.source
    
    //左边按钮标题
    leftButtonTitle: string
    
    //左边按钮点击事件
    onLeftButtonPress: function
    
    //右边按钮图标
    rightButtonIcon: Image.propTypes.source
    
    //右边按钮标题
    rightButtonTitle: string
    
    //右边按钮点击事件
    onRightButtonPress: function
    
    //包裹样式
    warpperStyle: [Object Object]

    四、Navigator组件

    1、注意事项:如果RN版本升级到0.43以上的话,Navigator已过期,不能直接从react-native里面获取了,而是作为一个单独的库模块,解决方案如下:

    //安装
    npm install react-native-deprecated-custom-components --save //已过期失效,推荐使用第二个命令进行安装
    yarn add react-native-deprecated-custom-components           //可使用
    
    //导入
    import {Navigator} from 'react-native-deprecated-custom-components'

    2、Navigator组件提供的属性如下:

    /**
    * 配置跳转动画  
    * (route, routeStack) => Navigator.SceneConfigs.FloatFromRight
    */
    configureScene: PropTypes.func,
    
    /**
    * 渲染场景
    * (route, navigator) =>
    *   <MySceneComponent title={route.title} navigator={navigator} />
    */
    renderScene: PropTypes.func.isRequired,
    
    /**
    * 配置路由
    */
    initialRoute: PropTypes.object,
    initialRouteStack: PropTypes.arrayOf(PropTypes.object),
    
    /**
    * 路由即将跳转时调用
    */
    onWillFocus: PropTypes.func,
    
    /**
    * 路由完成跳转时调用
    */
    onDidFocus: PropTypes.func,
    
    /**
    * 导航栏
    */
    navigationBar: PropTypes.node,
    
    /**
    * navigator对象
    */
    navigator: PropTypes.object,
    
    /**
    * 场景样式
    */
    sceneStyle: ViewPropTypes.style,    

    3、虽然Navigator组件很粗糙,但是它的定制性极强,可以很好解决NavigatorIOS组件不能跨平台和自定义的问题。Navigator组件只提供跳转功能,界面需要开发者自己去定制。使用步骤大致如下:

    //1、配置路由
    initialRoute={{component:this.props.component, passProps:{}}}
    
    //2、配置跳转
    configureScene={()=>{return Navigator.SceneConfigs.FloatFromBottom;}}
    
    //3、渲染场景
    renderScene={(route, navigator) => {
        // ...扩展符, 作用:如果是对象,就获取对象中所有值,如果是数组,就获取数组中所有值
       const Component = route.component; 
        return (
            <View style={{flex:1}}> //使用flex设置导航尺寸
                <Component navigator={navigator} route={route} {... route.passProps}>      
            </View>      
        )
    }

    4、Navigator组件支持的跳转方向和类型有很多,如下所示:

    Navigator.SceneConfigs.PushFromRight //(默认)
    Navigator.SceneConfigs.FloatFromRight
    Navigator.SceneConfigs.FloatFromLeft
    Navigator.SceneConfigs.FloatFromBottom
    Navigator.SceneConfigs.FloatFromBottomAndroid
    Navigator.SceneConfigs.FadeAndroid
    Navigator.SceneConfigs.HorizontalSwipeJump
    Navigator.SceneConfigs.HorizontalSwipeJumpFromRight
    Navigator.SceneConfigs.VerticalUpSwipeJump
    Navigator.SceneConfigs.VerticalDownSwipeJump

    5、导航过渡过程中,可以配置的回调函数如下:

    //每当导航切换完成或初始化之后,调用此回调,参数为新场景的路由
    onDidFocus function 
    
    //会在导航切换之前调用,参数为目标路由
    onWillFocus function 

    五、使用NavigatorIOS组件

    需求:新闻列表页跳转到新闻详情页。

    index.ios.js程序入口文件

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, { Component } from 'react';
    import NavigatorBar from './src/NavigatorBar'
    
    import {
      AppRegistry,
      View
    } from 'react-native';
    
    
    export default class ReactNativeDemo extends Component {
    
      render() {
        return (
            <NavigatorBar/>
        );
      }
    }
    
    AppRegistry.registerComponent('ReactNativeDemo', () => ReactNativeDemo);

    Navigator.js创建的NavigatorIOS导航栏组件文件

    import React, { Component } from 'react';
    import NewsHome from './NewsHome'
    
    import {
        NavigatorIOS
    } from 'react-native';
    
    export default class NavigatorBar extends Component{
    
        render(){
            return (
                <NavigatorIOS
                    style={{flex: 1}}          //设置导航栏样式
                    barTintColor={'purple'}    //设置导航栏颜色
                    titleTextColor={'white'}   //设置导航标题颜色
                    itemWrapperStyle={{backgroundColor:'orange'}} //设置导航页面背景颜色
                    initialRoute={{
                        component: NewsHome,   //设置路由,列表主页
                        title: "新闻列表",      //设置导航标题
                        passProps: {}          //传递数据
                    }}
                />
            );
        }
    }

    NewsHome.js新闻列表页文件

    import React, { Component } from 'react';
    import List from './List'
    
    import {
        View,
        StyleSheet
    } from 'react-native';
    
    /*
    * 此处使用扩展运算符...this.props,将属性navigator传递到List组件中,因为List组件中无法直接获取navigator组件对象
    * */
    export default class NewsHome extends Component{
        render() {
            return (
                <View style={styles.container}>
                    <List title="1、多地校长、专家在京探讨全息教育" {...this.props}/>
                    <List title="2、中国网络安全产业高峰论坛在京召开" {...this.props}/>
                    <List title="3、启动四天多 北京冬奥赛会志愿者报名人数超46万" {...this.props}/>
                    <List title="4、丰台消防救援支队筑牢辖区冬季火灾防线" {...this.props}/>
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        container:{
            marginTop: 64,
            backgroundColor:'white'
        }
    });

    List.js新闻列表组件文件

    import React, { Component } from 'react';
    import NewDetail from "./NewsDetail";
    
    import {
        StyleSheet,
        View,
        Text
    } from 'react-native';
    
    export default class List extends Component{
    
        constructor(props){
            super(props);
            this.push = this.push.bind(this); //绑定push事件,绑定方式有多种,这是其中方法之一
        }
    
        //跳转到详情页
        push(){
            let {navigator} = this.props; //作用域本地化
            navigator.push({              //navigator对象调用push函数
                component: NewDetail,     //新闻详情页
                title:"详情页",            //设置新闻详情页导航标题
                leftButtonTitle:"返回",    //设置新闻详情页导航左边按钮
                rightButtonTitle:"消息",   //设置新闻详情页导航右边按钮
                onLeftButtonPress:(() => navigator.pop()),          //返回上一页:列表主页,navigator对象调用pop函数
                onRightButtonPress:(() => alert("welcome to you")), //弹出吐司
                wrapperStyle: {backgroundColor:'yellow'}            //设置页面背景色
            })
        }
    
        render() {
            return (
                <View style={styles.list_item}>
                    <Text style={styles.list_font} onPress={this.push}>{this.props.title}</Text>
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        list_item: {
            height: 60,
            borderBottomWidth: 1,
            borderBottomColor: '#DDD',
            justifyContent: 'center'
        },
        list_font: {
            fontSize: 20,
            fontWeight: 'bold',
            color: 'black'
        }
    }); 

    NewsDetail.js新闻详情页文件

    import React, { Component } from 'react';
    
    import {
        StyleSheet,
        View
    } from 'react-native';
    
    export default class NewsDetail extends Component{
        render() {
            return (
                <View style={styles.container}/>
            )
        }
    }
    
    const styles = StyleSheet.create({
        container:{
            marginTop: 64,
            backgroundColor:'white'
        }
    });

    模拟器运行结果如下:

      

    六、使用Navigator组件

    1、无导航栏,只使用路由功能:

    inde.ios.js

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, { Component } from 'react';
    import NavigatorCustomBar from './src/NavigatorCustomBar'
    
    import {
      AppRegistry
    } from 'react-native';
    
    export default class ReactNativeDemo extends Component {
    
      render() {
        return (
            <NavigatorCustomBar/>
        );
      }
    }
    
    AppRegistry.registerComponent('ReactNativeDemo', () => ReactNativeDemo);

    NavigatorCustomBar.js

    import React, { Component } from 'react';
    import { Navigator } from 'react-native-deprecated-custom-components';
    
    import {
        View,
        Text,
        StyleSheet
    } from 'react-native';
    
    
    /*
    * 封装Navigator
    * 所有的切换动画都是从底部往上,回退时从上往底部
    * 这里通过{...passProps}模仿NavigatorIOS的passProps进行传值
    * initialRoute中的component: 传递的入口组件
    *
    * */
    export default class NavigatorCustomBar extends Component{
    
        render(){
            return (
                <Navigator
                    style={{flex:1}} //设置样式
                    initialRoute={{component:HomePage, passProps:{}}} //配置路由
                    configureScene={()=> {return Navigator.SceneConfigs.FloatFromBottom;}} //设置跳转动画
                    renderScene={(route, navigator) => {    //渲染页面场景
                        const Component = route.component;
                        return (
                            <Component navigator={navigator} route={route} {...route.passProps}/>
                        )
                    }}
                />
            )
        }
    }
    
    
    //首页
    class HomePage extends Component{
    
        render(){
            return (
                <View style={styles.home}>
                    <Text style={styles.font} onPress={()=>this.props.navigator.push({component: DetailPage})}>
                        HomePage
                    </Text>
                </View>
            );
        }
    }
    
    //详情页
    class DetailPage extends Component{
    
        render(){
            return (
                <View style={styles.detail}>
                    <Text style={styles.font} onPress={()=>this.props.navigator.pop()}>
                        DetailPage
                    </Text>
                </View>
            );
        }
    }
    
    //样式
    const styles = StyleSheet.create({
        home:{
            flex: 1,
            backgroundColor:'red',
            justifyContent: 'center',
            alignItems:'center',
        },
        detail:{
            flex: 1,
            backgroundColor:'green',
            justifyContent: 'center',
            alignItems:'center',
        },
        font:{
            fontSize:28,
            color:'white'
        }
    });

    2、有导航栏,且使用路由功能:

    inde.ios.js

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, { Component } from 'react';
    import NavigatorCustomBar from './src/NavigatorCustomBar'
    
    import {
      AppRegistry
    } from 'react-native';
    
    export default class ReactNativeDemo extends Component {
    
      render() {
        return (
            <NavigatorCustomBar/>
        );
      }
    }
    
    AppRegistry.registerComponent('ReactNativeDemo', () => ReactNativeDemo);

    NavigatorCustomBar.js

    import React, { Component } from 'react';
    import { Navigator } from 'react-native-deprecated-custom-components';
    
    import {
        View,
        Text,
        StyleSheet
    } from 'react-native';
    
    
    /*
    * 封装Navigator
    * 所有的切换动画采用默认方式
    * 这里通过{...passProps}模仿NavigatorIOS的passProps进行传值
    * initialRoute中的component: 传递的入口组件
    * */
    export default class NavigatorCustomBar extends Component{
    
        //1、路由初始化
        initialRoute = {
            name:"HomePage",    //路由名称
            component:HomePage, //路由页面
            index:0,            //页面索引
            passProps:{leftTitle:"返回",midTitle:"首页",rightTitle:""} //透传数据
        };
    
        //2、动画初始化
        configureScene = () => {
            return Navigator.SceneConfigs.PushFromRight;
        }
    
        //3、场景初始化
        renderScene = (route, navigator) => {
            const Component = route.component;
            return <Component navigator={navigator} route={route} {...route.passProps}/>
        }
    
        //4、Mapper初始化
        navBarRouteMapper = {
            //左边按钮
            LeftButton(route, navigator, index){
                if (index <= 0) return;
                return (
                        <Text style={styles.left} onPress={ () => navigator.pop()}>
                            {route.passProps.leftTitle}
                        </Text>
                );
            },
            //中间标题
            Title(route, navigator){
                return (
                        <Text style={styles.mid}>
                            {route.passProps.midTitle}
                        </Text>
                );
            },
            //右边按钮
            RightButton(route, navigator){
                if(!route.passProps.rightTitle) return;
                return (
                        <Text style={styles.right} onPress={() => alert('welcome to me!')}>
                            {route.passProps.rightTitle}
                        </Text>
                );
            }
        };
    
        render(){
            return (
                <Navigator
                    style={{flex:1}}                     //设置样式
                    initialRoute={this.initialRoute}     //配置路由
                    configureScene={this.configureScene} //设置跳转动画
                    renderScene={this.renderScene}       //渲染页面场景
                    navigationBar={                      //设置导航栏Mapper
                        <Navigator.NavigationBar
                            style={styles.navContainer}
                            routeMapper={this.navBarRouteMapper}/>
                    }
                />
            )
        }
    }
    
    
    //首页
    class HomePage extends Component{
    
        //设置详情页导航栏
        pushToDetailPage(){
            this.props.navigator.push({
                index:1,
                component: DetailPage,
                passProps:{
                    leftTitle: this.props.leftTitle,
                    midTitle:"详情",
                    rightTitle:"消息"
                }
            })
        }
    
        render(){
            return (
                <View style={styles.home}>
                    <Text style={styles.font} onPress={this.pushToDetailPage.bind(this)}>
                        this is HomePage
                    </Text>
                </View>
            );
        }
    }
    
    //详情页
    class DetailPage extends Component{
    
        render(){
            return (
                <View style={styles.detail}>
                    <Text style={styles.font} onPress={()=>this.props.navigator.pop()}>
                        this is DetailPage
                    </Text>
                </View>
            );
        }
    }
    
    //样式
    const styles = StyleSheet.create({
        navContainer:{
            height:64,
            backgroundColor:'#41ABF7'
        },
        left:{
            paddingLeft:20,
            paddingTop:10,
            flex:1/3,
            fontSize:20,
            color:'white'
        },
        mid:{
            paddingTop:10,
            flex:1/3,
            fontSize:20,
            color:'white'
        },
        right:{
            paddingRight:20,
            paddingTop:10,
            flex:1/3,
            fontSize:20,
            color:'white'
        },
        home:{
            flex: 1,
            marginTop:64,
            backgroundColor:'orange',
            justifyContent: 'center',
            alignItems:'center',
        },
        detail:{
            flex: 1,
            marginTop:64,
            backgroundColor:'brown',
            justifyContent: 'center',
            alignItems:'center',
        },
        font:{
            fontSize:28,
            color:'white'
        }
    });

  • 相关阅读:
    关于如何学习C语言
    2020软件工程作业04
    2020软件工程作业03
    2020软件工程作业02
    2020软件工程作业01
    3.语法树,短语,直接短语,句柄
    2.文法和语言
    Linux——如何将Red Hat Enterprise Linux 6的语言改为中文?
    编译原理概述
    编译原理概述-第一次作业
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/12017932.html
Copyright © 2020-2023  润新知