React Native自定义导航栏

之前我们学习了可触摸组件和页面导航的使用的使用:
从零学React Native之09可触摸组件

从零学React Native之03页面导航

经过之前的学习, 我们可以完成一个自定义导航栏了, 效果如下:
React Native自定义导航栏

我们需要创建一个 NaviBar.js 用来显示顶部的导航栏, 还需要四个界面(Page1.js,Page2.js,Page3.js,Page4.js)。 当然还需要修改index.android.js或者index.ios.js 用来处理4个界面的切换。

导航栏NaviBar 实现

这里, 我们就假设应用有4个栏目, 每个按钮的宽高比为 4:3
直接贴代码了:

import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    View,
    Text,
    TouchableHighlight,
} from 'react-native';

var Dimensions = require("Dimensions");
var totalWidth = Dimensions.get('window').width;// 屏幕宽度
let naviButtonWidth = totalWidth / 4;    //计算导航条每个宽度
let naviButtonHeight = naviButtonWidth * 0.75;   // 导航条每个高度
export  default class NaviBar extends Component {
    // 构造
    constructor(props) {
        super(props);
        this._tab0Pressed = this._tab0Pressed.bind(this);
        this._tab1Pressed = this._tab1Pressed.bind(this);
        this._tab2Pressed = this._tab2Pressed.bind(this);
        this._tab3Pressed = this._tab3Pressed.bind(this);
    }

    //四个按钮 被按下时处理函数
    _tab0Pressed() {
        this.props.onNaviBarPress(0);
    }

    _tab1Pressed() {
        this.props.onNaviBarPress(1);
    }

    _tab2Pressed() {
        this.props.onNaviBarPress(2);
    }

    _tab3Pressed() {
        this.props.onNaviBarPress(3);
    }

    render() {
        //通过属性得知哪个导航按钮是当前导航页, 这个导航用灰色背景
        //利用JavaScript数组的map函数,从一个数组对应生成另一个数组buttonColors
        // 看不懂该函数的,看下面的解释
        var buttonColors = this.props.naviBarStatus.map(function (aNumber) {
            if (aNumber == 0) return 'white';
            return 'gray';
        });
        return (
            //根View
            <View style={styles.naviRow}>
                <TouchableHighlight onPress={this._tab0Pressed}>
                    <View style={[styles.button,{backgroundColor:buttonColors[0]}]}>
                        <Text style={styles.textStyle1}>
                            条目一
                        </Text>
                    </View>
                </TouchableHighlight>
                <TouchableHighlight onPress={this._tab1Pressed}>
                    <View style={[styles.button,{backgroundColor:buttonColors[1]}]}>
                        <Text style={styles.textStyle1}>
                            条目二
                        </Text>
                    </View>
                </TouchableHighlight>
                <TouchableHighlight onPress={this._tab2Pressed}>
                    <View style={[styles.button,{backgroundColor:buttonColors[2]}]}>
                        <Text style={styles.textStyle1}>
                            条目三
                        </Text>
                    </View>
                </TouchableHighlight>
                <TouchableHighlight onPress={this._tab3Pressed}>
                    <View style={[styles.button,{backgroundColor:buttonColors[3]}]}>
                        <Text style={styles.textStyle1}>
                            条目四
                        </Text>
                    </View>
                </TouchableHighlight>
            </View>
        );
    }
}
// 声明属性, 方便使用当前组件
NaviBar.propTypes = {
    naviBarStatus: React.PropTypes.arrayOf(React.PropTypes.number).isRequired,
    onNaviBarPress: React.PropTypes.func.isRequired
};

//样式 
const styles = StyleSheet.create({
    naviRow: {
        flexDirection: 'row'
    },
    button: {
        width: naviButtonWidth,
        height: naviButtonHeight,
        justifyContent: 'center'
    },
    textStyle1: {
        fontSize: 20,
        textAlign: 'center'
    }
});

上面用到了, Map函数 ,
Map函数的作用是按照某种关系从原数组”映射”出新数组. 如下面求平方的例子:

var data= [1,2,3,4];
var newArray=data.map((item)=>{return item*item});
console.log(newArray);  //输出[1,4,9,16]

统一处理四个界面的切换

我们需要在index.android.js 或者index.ios.js 这个代码比较简单, 只需要导入四个界面, 用Navigator组件切换就可以了。

import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    Navigator
} from 'react-native';

import Page1 from './Page1';
import Page2 from './Page2';
import Page3 from './Page3';
import Page4 from './Page4';
class AwesomeProject extends Component {
    //告知Navigator 模块切换时的效果
    configureScene() {
        return Navigator.SceneConfigs.FadeAndroid;
    }
    //根据传递的信息, 处理界面的切换
    renderScene(router, navigator) {
        this._navigator = navigator;
        switch (router.name) {
            case 'Page1':
                return <Page1 navigator={navigator}/>;
            case 'Page2':
                return <Page2 navigator={navigator}/>;
            case 'Page3':
                return <Page3 navigator={navigator}/>;
            case 'Page4':
                return <Page4 navigator={navigator}/>;
        }
    }
    render() {
        return (
            //根View
            <Navigator
                initialRoute={{name:'Page1'}}
                configureScene={this.configureScene}
                renderScene={this.renderScene}/>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);

界面

上面的代码需要引入Page1 - Page4, 这个四个界面非常相似, 我们只贴其中一个了.
Page1.js

import React, { Component } from 'react';
import {
    View,
    StyleSheet,
} from 'react-native';
import NaviBar from './NaviBar';

export  default class Page1 extends Component {
    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.onNaviBarPress = this.onNaviBarPress.bind(this);
    }

    render() {
        // 不同的Page,需要修改下面的这个数组, 通过数组控制导航栏条目显示状态
        var naviStatus = [1, 0, 0, 0];
        return (
            <View style={styles.container}>
                <NaviBar naviBarStatus={naviStatus}
                         onNaviBarPress={this.onNaviBarPress}/>
                <View style={styles.whatLeft}/>
            </View>
        );
    }
    //不同的page需要修改返回值
    onNaviBarPress(aNumber) {
        switch (aNumber) {
            case 0:
                return;
            case 1:
                //通过replace切换
                this.props.navigator.replace({
                    name: 'Page2'
                });
                return;
            case 2:
                this.props.navigator.replace({
                    name: 'Page3'
                });
                return;
            case 3:
                this.props.navigator.replace({
                    name: 'Page4'
                });
                return;
        }
    }
}
const styles = StyleSheet.create({
    container: {
        flex: 1
    },
    whatLeft: {  // 组件定义了一个上边框
        flex: 1,
        borderTopWidth: 1,
        borderColor: 'black',
        backgroundColor:'red' //每个界面背景颜色不一样
    }
});

顺便指出两点: 当根View没有指定背景色时, 默认值是一种灰色; 当子View没有指定背景色时,会继承父View的背景色。

更多精彩请关注微信公众账号likeDev,公众账号名称:爱上Android。
React Native自定义导航栏

上一篇:React Native等比放大不丢失图片


下一篇:[Android]使用Dagger 2依赖注入 - 图表创建的性能(翻译)