【稀饭】react native 实战系列教程之Navigator实现页面跳转

原创 2016年09月18日 14:59:27

主界面开发

上一节,我们已经完成了首页的开发,现在,我们继续完成主界面的开发,就是添加底部‘首页’和‘我的’两个tabbar。

在js/文件夹下,新建MainScene.js文件

import React,{Component} from 'react';
import {
    View,
    Text,
    TouchableOpacity,
    Image,
    StyleSheet,
}from 'react-native';

export default class MainScene extends Component{
    constructor(props){
        super(props);
        this.state={
            tabIndex:0,
        }

    }

    render(){
        return(
            <View style={{flex:1,justifyContent:'flex-end'}}>

                <View style={{backgroundColor:'#d5d5d5',height:1,}}/>
                <View style={{height:55,flexDirection:'row',justifyContent:'center',alignItems:'center'}}>
                    <TouchableOpacity style={{flex:1}} activeOpacity={0.6} onPress={this._onTabPress.bind(this,0)}>
                        <View style={styles.ItemView}>
                            <Image
                                style={{height:30,width:30}}
                                source={this.state.tabIndex==0?require('../img/icon_home_select.png'):require('../img/icon_home_unselect.png')}
                            />
                            <Text style={this.state.tabIndex==0?styles.TabTextSelect:styles.TabTextUnSelect}>首页</Text>
                        </View>
                    </TouchableOpacity>
                    <TouchableOpacity style={{flex:1}} activeOpacity={0.6} onPress={this._onTabPress.bind(this,1)}>
                        <View style={styles.ItemView}>
                            <Image
                                style={{height:30,width:30}}
                                source={this.state.tabIndex==0?require('../img/icon_my_unselect.png'):require('../img/icon_my_select.png')}
                            />
                            <Text style={this.state.tabIndex==0?styles.TabTextUnSelect:styles.TabTextSelect}>我的</Text>
                        </View>
                    </TouchableOpacity>
                </View>

            </View>

        );
    }

    //tab点击事件
    _onTabPress(index){
//console.log('index = '+ index);
        //this.viewPager.setPage(index);
        this.setState({
            tabIndex:index,
        });
    }

}
var styles = StyleSheet.create({
    ItemView:{
        flex:1,
        justifyContent:'center',
        alignItems:'center',
        marginTop:3,
    },
    TabTextSelect:{
        flex:1,
        textAlign:'center',
        alignItems:'center',
        color:'#ff5722',
    },
    TabTextUnSelect:{
        flex:1,
        textAlign:'center',
        alignItems:'center',
        color:'#d5d5d5',
    },
});

主要绘制了,底部两个带图标的选项卡,根据state.tabIndex的索引,动态修改tab的icon和文字样式,然后将index.android.js的启动页修改为MainScene,运行程序,结果如下

主界面

然后就是给tab上方添加内容页面

MainScene->render

render(){
    var page = this.state.tabIndex===0?<HomeScene/>:<MyScene />;
    return(
        <View style={{flex:1,justifyContent:'flex-end'}}>
            {page}
            ...//省略其它代码
        </View>

    );
}

这里我们使用动态渲染页面的方式,当选项进行切换时,根据tabIndex索引值,获取到对应的页面进行显示。

ok,添加完之后,运行,现在的效果如下

主界面

到此,主界面的功能基本完成,只是点击列表item没反应,因为,我们还没给页面设计跳转功能,下面我们将来说说应用的导航器。

应用导航器

关于react-native页面跳转和数据传递,使用到的是Navigator这个组件。它可以帮我们在在不同的页面进行切换,只要指定了路由,在renderScene方法就会渲染对应的页面。更多详细介绍

由于我们的应用要跳转的地方会有很多,所以我们需要为APP定义一个统一的路由入口。

我们先抽出定义一个应用的导航器AppNavigator,在js/component/下新建AppNavigator.js

import React,{Component} from 'react';
import {
    Navigator,
} from 'react-native';
//应用导航器
export default class AppNavigator extends Component{
    constructor(props){
        super(props);
    }
    render(){
        return(
            <Navigator 
                initialRoute={
                    {
                        id:this.props.id,
                        data:this.props.data,
                        name:this.props.name,
                        component:this.props.component
                    }
                }
                renderScene={(route,navigator)=>{
                  let Scene = route.component;
                  return <Scene id={route.id} data={route.data} name={route.name} navigator={navigator}/>
                }}
                style={{flex:1,}}
                configureScene={(route) => {
                  if(route.sceneConfig){
                    return route.sceneConfig;
                  }
                  return Navigator.SceneConfigs.HorizontalSwipeJump;
                }}
              />
            );
    }
}

我们指定了路由数据结构如下(这个数据结构根据自己的需求去定义),

{
    id:this.props.id,
    data:this.props.data,
    name:this.props.name,
    component:this.props.component
}

页面的唯一识别id,要传递的数据data(可以任意类型的数据),页面的名称name(页面的名称,这里用于TitleBar显示标题名称),要渲染的页面组件component。重要的部分在于renderScene函数。

renderScene={(route,navigator)=>{
  let Scene = route.component;
  return <Scene id={route.id} data={route.data} name={route.name} navigator={navigator}/>
}}

这里我们获取到route传过来的component,然后将该component当作一个view节点返回回去,并且给该组件传入了一组props,这样在该Scene下,就可以通过this.props获取到id\data\name\navigaror.当获取到navigaror对象之后,我们可以进行push\pop操作,实现页面的跳转\回退功能。

configureScene函数是配置页面跳转时的动画效果

使用导航器进行页面跳转

导航器写好之后,我们就该思考将它作为应用的统一入口应该放置在哪合适。

如果你在使用Navigator过程中,碰到跳转时,某些元素比如标题、底部的tabbar,在跳转之后还需要特殊处理(隐藏),那么可能是你把Navigator放的位置不够准确。就像我之前写的时候,将Navigator放在了HomeScene中,导致点击影片item页面跳转之后(跳到详情),底部的tabbar还显示着。一开始想的是在跳转之后将tabbar隐藏,但是这样就会有闪动的情况,后来把Navigator位置改正之后,就达到想要的结果了。

既然作为程序的统一路由入口,那么我们是不是有理由这么想,它也应该是放在程序的启动处。是的,将它放在index.android.js。

import AppNavigator from './js/component/AppNavigator';
import MainScene from './js/MainScene';
class XiFan extends Component {

  render(){
    return(
        <AppNavigator id='MainScene' data='' name='' component={MainScene}/>
    );
  }
}

将导航器的初始路由页面设置为MainScene,由于是主界面,所以不用传递data\name数据。

然后打开MainScene,修改代码

render(){
    var page = this.state.tabIndex===0?<HomeScene navigator={this.props.navigator}/>:<MyScene />;
    ....//省略其它代码
}

增加了navigator参数,而this.props.navigator实例对象是来至于AppNavigator的renderScene中navigator,这样我们就把navigator实例对象传递给了HomeScene。再打开HomeScene,要修改的地方有两处

HomeScene->render()

  • 让TitleBar具有返回/回退功能

将navigator对象传递给TitleBar

<TitleBar title="首页" subtitle="看韩剧,上稀饭" subScene={false} navigator={this.props.navigator}/>

再打开TitleBarComponent ->_onIconClick()

//返回按钮事件
_onIconClick(){
    var navigator = this.props.navigator;
    if(navigator){
        navigator.pop();
    }
}

在获取到navigator对象后,进行pop操作,就可以返回了。

  • 将navigator对象传递给DramaComponent
<ViewPagerAndroid
    ...//省略其它代码
>
    <View style={{flex:1}}>
        <DramaComponent url='/hanju/new/' navigator={this.props.navigator}/>
    </View>
    <View style={{flex:1}}>
        <DramaComponent url='/hanju/renqi/' navigator={this.props.navigator}/>
    </View>
</ViewPagerAndroid>

这样DramaComponent也有了navigator实例对象,打开DramaComponent,我们给它item点击事件添加跳转到详情的功能。

DramaComponent -> _onItemPress

//item 点击跳转
_onItemPress(movie){
    const navigator = this.props.navigator;
    if(navigator){
        navigator.push({
            id:'DramaDetailScene',
            data:movie,
            name:movie.name,
            component:DramaDetailScene
        });
    }
}

也就是,如果是由Navigator导航的组件,那么该组件本身就有Navigator对象,并由this.props.navigator取得,如果是导航组件的内部组件要使用导航对象,那么就要给该组件增加props属性

navigator={this.props.navigator}

这里item点击跳转的是详情页DramaDetailScene,我们先简单的写下这个页面,后面在具体实现详情页

新建DramaDetailScene.js

import React,{Component} from 'react';
import {
    View,
    Text
} from 'react-native';
import TitleBar from './component/TitleBarComponent';
export default class DramaDetailScene extends Component{

    constructor(props) {
        super(props);
    }

    render(){
        return (
            <View>
                <TitleBar title={this.props.name} subtitle='' subScene={true} navigator={this.props.navigator}/>
                <Text>影片详情页</Text>
            </View>
        );
    };
}

这样,我们就实现了页面的跳转功能,但是由于Android还有物理返回键,因此要实现按下返回键时退出当前页、在主界面 “再按一次退出程序” 的功能。

首先要拦截返回键事件,在主界面MainScene,添加如下代码

import {
    ...//省略其它代码
    BackAndroid,
    Platform,
    ToastAndroid
} from 'react-native';

export default class MainScene extends Component{
    ...//省略其它代码
    componentDidMount(){
        this._addBackAndroidListener(this.props.navigator);
    }

    componentWillUnmount(){
        this._removeBackAndroidListener();
    }

    //监听Android返回键
    _addBackAndroidListener(navigator){
        if(Platform.OS==='android'){
            var currTime = 0;
            BackAndroid.addEventListener('hardwareBackPress',()=>{
                if(!navigator){return false;}
                const routers = navigator.getCurrentRoutes();
                if(routers.length == 1){//在主界面
                    var nowTime = (new Date()).valueOf();
                    if(nowTime - currTime > 2000){
                        currTime = nowTime;
                        ToastAndroid.show("再按一次退出程序",ToastAndroid.SHORT);
                        return true;
                    }
                    return false;
                }else{//在其他子页面
                    navigator.pop();
                    return true;
                }
            });
        }
    }
    //移除监听
    _removeBackAndroidListener(){
        if (Platform.OS === 'android') {
            BackAndroid.removeEventListener('hardwareBackPress');
        }
    }
}

总结

至此,应用的页面跳转已经实现了,navigator对于react native 来说还是比较重要的一个组件,因为每个应用都会涉及到页面的切换,而这都离不开对navigator的使用。看完本节的内容,应该对navigator的使用已经掌握得差不多了,下一节,我们将对详情页进行开发,其中重要的是学习如何使用原生代码为react native提供原生能力。

版权声明:本文为博主原创文章,未经博主允许不得转载。

undefined is not a function (evaluating 'this.props.renderScene(route,this)')

缺少renderScene函数, var NV = React.createClass({ render: function(){ return(

渲染世界的OPENGL<12> 一些有趣的纹理着色器

从着色器访问纹理贴图是非常简单的。纹理坐标将会作为属性传递到我们的顶点着色器,在片段着色器当中,这些属性通常是在顶点之间进行平滑插值的。片段着色器使用这些差值纹理坐标来对纹理进行采样。(1)只处理纹理...

WEEX|简单界面的实现与页面跳转

在了解了初始化工程后,我们开始实现简单界面的搭建与页面跳转
  • zpfvs1
  • zpfvs1
  • 2016年11月14日 15:57
  • 1717

Android-Weex之多应用选择窗口处理及页面之间的跳转

weex在Android开发中,如何进行多页面跳转和设置唯一应用模式(如何避开多应用选择模式)...
  • byxyrq
  • byxyrq
  • 2017年05月11日 14:23
  • 2199

Weex Android SDK源码分析之Module(navigator)

之前已经介绍了module中的model,本篇博文介绍Weex Moudle中的navigator使用与源码分析。...

JS中navigator对象详解

Navigator详解,IE11,chrome和firefox浏览器下 //属性 var appCodeName= window.navigator.appCod...

TabBar切换页的实现——React-native-tab-navigator的使用

在构建TabBar的方式上,使用React-native-tab-navigator(https://github.com/exponentjs/react-native-tab-navigator)...

React-Native学习笔记之:使用Tab react-native-tab-navigator框架

在React Native中,我们通常使用react-native-tab-navigator来做底部导航栏效果,使用前先要在项目中引入对应 依赖库, 引用方法: windows环境,cmd命令窗口,...
  • true100
  • true100
  • 2017年03月29日 16:39
  • 7314

React-Native学习笔记之:导航器Navigator实现页面间跳转

Navigator用来实现不同页面的切换,想设置Navigator,必须确定一个或多个调用routes对象,去定义每个场景。 还可以利用renderScene方法,导航栏可以根据指定的路由来渲染场景。...
  • true100
  • true100
  • 2017年04月17日 10:03
  • 2261

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【稀饭】react native 实战系列教程之Navigator实现页面跳转
举报原因:
原因补充:

(最多只允许输入30个字)