关闭

React-native 尝鲜计划-场景切换(Navigator)

标签: react-nativenode.js跨平台
3045人阅读 评论(0) 收藏 举报
分类:

在上篇文章《react-native 尝鲜计划-环境搭建》中讲述了react-native 的环境搭建,并初始化了 react-native 的第一个项目。如果你已经完成了上一篇文章的学习,并且成功调试第一个 “hello world” 项目,你已成功地经迈出第一步,接下来的学习就会顺利得多。在我成功调试出第一个项目之后,连蒙带差的走读了下原生代码和 index.android.js 代码,脑海里有很多疑问,第一个疑问就是:react-native 如何做多个页面跳转的?相信你也一样,带着带着问题来学习是比较有动力的一种学习方式。
  • 切换场景demo

本章重点是 demo,react-native场景切换的demo下载地址:https://github.com/liuguangli/RN-DemoForChangeSence

先跑出效果,从现象到本质符合人类的一般认知规律,建议读者下载demo自行研究,我也希望你研究demo之后不用读后文了。


  • Navigator 热身

 react-natvie 中来切换页面的一个重要组件就是Navigator,这里只介绍demo中用到的几个重要的属性和方法,详细的可以点击这里可以看官方文档介绍

1 initialRoute

 Navigator 的一个属性,用来描述Navigator场景栈中的第一个场景信息route。一个结构类型,一个般要提供 name,index等描述信息。

2 renderSence

 Navigator 的一个方法,在Navigator创建或 push(route) /pop()方法调用的时候回调renderSence(route, navigator)方法,出入两个参数:route和 navigator 本身。

3 push

  场景跳转:指定一个route, 在回调方法 renderSence()中根据 route 返回指定的 sence,sence可以是任何可视化组件或容器。 

4 pop

 回退到上一个场景。


  • 一步一步的来实现这个demo

1. 入口(index.android.js)

 我们先完成 react 的第一个入口组件,将其注册到到 app上。

 首先引入我们要使用的组建:

 

var React = require('react-native');
var {
  AppRegistry,
  Navigator,
} = React; 


AppRegistry,用于注册我们的程序入口组件。Navigator,是我们使用的第一个组件,用于操作场景转换。

创建组件:


// 创建入口组件
var ChangeSenceProject = React.createClass({
  render: function() {
    var initialRoute = {name:"A"};
    return (<Navigator 
     initialRoute={initialRoute}
     renderScene={RouteMapper}
     />)
  },

});
注册到应用:
//注册项目
AppRegistry.registerComponent('ChangeSenceProject', () => ChangeSenceProject);
注意到我们在 ChangeSenceProject 的入口方法 render 中使用 Navigator 组件,并且提供第一个route对象:{name:"A"}和一个renderSence方法,这个方法必须要实现,所以我们要在React.createClass之前先实现renderSence方法,我们方法名定义为:RouteMapper
//Navigator跳转规则
var RouteMapper = function(route,navigation,onComponent){
   //todo ,根据route 返回相应的场景
};

这里我门不实现逻辑,等我门完成两个场景页面的编写再来实现这里的逻辑。

2. Android native

我们使用 ReactRootView 来承载我们的交互组件。

main_activity.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MoviesApp">
    <com.facebook.react.ReactRootView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/react_root_view"/>
</RelativeLayout>
MainActivity.java
package com.changesence;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {

    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(true)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();

        ((ReactRootView) findViewById(R.id.react_root_view))
                .startReactApplication(mReactInstanceManager, "ChangeSenceProject", null);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
            mReactInstanceManager.showDevOptionsDialog();
            return true;
        }
        return super.onKeyUp(keyCode, event);
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onPause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onResume(this);
        }
    }

    @Override
    public void onBackPressed() {
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onBackPressed();
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }
}

注意:startReactApplication()方法的第一个参数必须和我们在 AppRegistry 中注册的项目名一样。
到此为止,项目可以运行起来了,不过你看到的是空白页面,因为RouteMapper还没有任何实现,我们需要提供场景逻辑。

3 . 场景A(SenceA.js)

在场景A中我们只做简单的显示一行文字,然后点击文字跳转到场景B。

直接上代码:SenceA.js

'use strict';
var React = require('react-native');
var {
  TouchableNativeFeedback,
  Navigator,
  StyleSheet,
  Text,
  View,
} = React;
var SenceA = React.createClass({
  //touch事件回调
 touch: function(target:Object){
  this.props.navigator.push(
   {
    title:"B",
    name:"B"
   } 
  );
 },
 render: function() {
 	return (<View style={styles.container}>
      <TouchableNativeFeedback
       onPress={this.touch}>
       <View>
         <Text>' this is SenceA,click to SenceB'</Text>
       </View>  
      </TouchableNativeFeedback> 
      </View>);
 },
});
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
});
//导出场景,供外部require
module.exports = SenceA;

4 场景B

场景比和场景A一样,显示内容不一样。直接上代码:SenceB.js


'use strict';
var React = require('react-native');
var {
  TouchableNativeFeedback,
  Navigator,
  StyleSheet,
  Text,
  View,
} = React;

var SenceB = React.createClass({
 touch: function(target:Object){
   if (this.props.navigator.getCurrentRoutes().length>1) {
    this.props.navigator.pop();
   };
  
 },
 render: function() {
 	return (<View style={styles.container}>
      <TouchableNativeFeedback
       onPress={this.touch}>
       <View>
         <Text>' this is sence B,click to sence A'</Text>
       </View>  
      </TouchableNativeFeedback> 
      </View>);
 },
});
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#FFFC00',
  },
});
module.exports = SenceB;
5 在 index.android.js 引入场景,完善RouteMapper逻辑。

引入场景:

//引入场景文件
var SenceA = require('./SenceA');
var SenceB = require('./SenceB');
完善RouteMapper:

//Navigator跳转规则
var RouteMapper = function(route,navigation,onComponent){
   _navigator = navigation;
    if (route.name === 'A') {
      console.log("return SenceA");
      return (
       <SenceA navigator={navigation} />
      );
    } else if (route.name==="B"){
      console.log("return SenceB");
      return (
        <SenceB navigator={navigation} />
      );
    } 
};


  • 武器准备


如果 react-navtive 是移动应用开发的另一个战场的话,那么走到这里我们算是已经知道战场在哪里了,接下来事就是怎么操练武器了。要熟悉react-native的编程,我门先要掌握以下武器:

1 js基础

2 node.js

3 jsx 语法

4 flexbox布局

注:react-native 出来不久文档资料不多,文章不足之处欢迎指正,一起研究新技术、新思想。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:39144次
    • 积分:817
    • 等级:
    • 排名:千里之外
    • 原创:37篇
    • 转载:0篇
    • 译文:2篇
    • 评论:36条
    文章分类
    最新评论