1. 程式人生 > >React Native:自定義一個導航欄,改變狀態列背景,隱藏狀態列

React Native:自定義一個導航欄,改變狀態列背景,隱藏狀態列

設計開發過程中,導航欄都會有所不同,這時候使用RN就需要自定義一個想要的導航欄了,RN中文網有講專門ios的導航欄(NavigatorIOS),可以不用自定義。

首先定義自定義導航欄的一些屬性的約束,記得npm install --save prop-types然後引入import PropTypes from 'prop-types';

static propTypes={  //自定義屬性
        title:PropTypes.string,
        titleView:PropTypes.element,//要求屬性是某個 React 元素
        leftButton:PropTypes.element, //左邊控制元件
        rightButton:PropTypes.element, //右邊控制元件
    }

    constructor(props){
        super(props);
        this.state={
            title:''
        }
    }

然後設定邏輯,組裝出一個導航欄的模樣,下面這樣就是組裝好了左邊一個元件,中間一個標題或者元件,右邊一個元件的樣子,最後return:

 render(){
        //如果有給出titleView的值就用這個值,反之就使用title的值為標題
        let titleView = this.props.titleView?this.props.titleView:<Text>{this.props.title}</Text>
        let content = <View style={styles.navBar}>
            {this.props.leftButton}
            <View style={styles.titleViewContainer}>
                {titleView}
            </View>
            {this.props.rightButton}
             </View>
        return(
            <View>
                {content}
            </View>
        )
    }

這是上面自定義導航欄的樣式,還有兩個常量用於在不同系統顯示不同的高:

const styles = StyleSheet.create({
    navBar:{
        justifyContent: 'space-between',
        alignItems:'center',
        height:Platform.OS==='IOS'?NAV_BAR_HEIGHT_IOS:NAV_BAR_HEIGHT_ANDROID,
        backgroundColor:'#ff7888',
        flexDirection: 'row' //元件水平顯示
    },
    titleViewContainer:{
        justifyContent: 'center',
        alignItems: 'center',//水平
        position: 'absolute',
        left:40,
        right:40,
        top:0,
        bottom:0
    }
})
const NAV_BAR_HEIGHT_ANDROID=50;
const NAV_BAR_HEIGHT_IOS=44;

接下來只需要呼叫,並設定想要的屬性就行了:

import React, {Component} from 'react';
import {StyleSheet, View, TouchableOpacity, Image} from 'react-native';
import MyNavigationBar from './myNavigationBar';

export default class supermarket extends Component<Props> {

    renderButton(image){
        return (
            <TouchableOpacity>
                <Image source={image}  style={styles.myImage}/>
            </TouchableOpacity>
        )
    }

    render() {
        return (
            <View style={styles.container}>
                <MyNavigationBar
                    title='我是標題'
                    leftButton={ //導航欄左方
                        this.renderButton(require("../../images/jiantou.png"))
                    }
                    rightButton={
                        this.renderButton(require("../../images/star.png"))
                    }
                />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
    },
    myImage:{
        width:22,
        height:22,
        margin:5
    }
});

效果如下 :

發現狀態列背景和導航欄不一樣,接下來改變狀態列背景,使其一致:

建立一個常量,新增狀態列的屬性設定,然後加入到propTypes中:

const StatusBarShape={ //設定狀態列
    backgroundColor:PropTypes.string, //設定狀態列的背景色
    barStyle:PropTypes.oneOf(['default', 'light-content', 'dark-content']), //狀態列樣式 default	預設的樣式(IOS為白底黑字、Android為黑底白字)light-content	黑底白字 dark-content	白底黑字(需要Android API>=23)
    hidden:PropTypes.bool,   //狀態列是否隱藏
    translucent:PropTypes.bool,////指定狀態列是否透明。設定為true時,應用會在狀態列之下繪製(即所謂“沉浸式”——被狀態列遮住一部分)。常和帶有半透明背景色的狀態列搭配使用
}

設定一些狀態列的預設值:

 static defaultProps={  //statusBar設定一些沒有設定時候的預設值
        statusBar:{
            hidden:false,
            barStyle: 'light-content'
        }
    }

在render中加入狀態列:

在呼叫的地方設定狀態列引數:

最終執行效果:

全部程式碼:

import React, {Component} from 'react';
import {StyleSheet, View, Text, Platform, StatusBar} from 'react-native';
import PropTypes from 'prop-types';

const NAV_BAR_HEIGHT_ANDROID=50;
const NAV_BAR_HEIGHT_IOS=44;
const StatusBarShape={ //設定狀態列
    backgroundColor:PropTypes.string, //設定狀態列的背景色
    barStyle:PropTypes.oneOf(['default', 'light-content', 'dark-content']), //狀態列樣式 default	預設的樣式(IOS為白底黑字、Android為黑底白字)light-content	黑底白字 dark-content	白底黑字(需要Android API>=23)
    hidden:PropTypes.bool,   //狀態列是否隱藏
    translucent:PropTypes.bool,////指定狀態列是否透明。設定為true時,應用會在狀態列之下繪製(即所謂“沉浸式”——被狀態列遮住一部分)。常和帶有半透明背景色的狀態列搭配使用
}
export default class myNavigationBar extends Component<props>{

    static propTypes={  //自定義屬性
        title:PropTypes.string,
        titleView:PropTypes.element,//要求屬性是某個 React 元素
        leftButton:PropTypes.element, //左邊控制元件
        rightButton:PropTypes.element, //右邊控制元件
        statusBar: PropTypes.shape(StatusBarShape),//形狀的約束
    }

    static defaultProps={  //statusBar設定一些沒有設定時候的預設值
        statusBar:{
            hidden:false,
            barStyle: 'light-content'
        }
    }

    constructor(props){
        super(props);
        this.state={
            title:'',
        }
    }

    render(){
        let statusBar = <View style={styles.statusBarStyle}>
            <StatusBar {...this.props.statusBar} />
        </View>
        //如果有給出titleView的值就用這個值,反之就使用title的值為標題
        let titleView = this.props.titleView?this.props.titleView:<Text>{this.props.title}</Text>
        let content = <View style={styles.navBar}>
            {this.props.leftButton}
            <View style={styles.titleViewContainer}>
                {titleView}
            </View>
            {this.props.rightButton}
             </View>
        return(
            <View>
                {statusBar}
                {content}
            </View>
        )
    }

}

const styles = StyleSheet.create({
    navBar:{
        justifyContent: 'space-between',
        alignItems:'center',
        height:Platform.OS==='IOS'?NAV_BAR_HEIGHT_IOS:NAV_BAR_HEIGHT_ANDROID,
        backgroundColor:'#ff7888',
        flexDirection: 'row' //元件水平顯示
    },
    titleViewContainer:{
        justifyContent: 'center',
        alignItems: 'center',//水平
        position: 'absolute',
        left:40,
        right:40,
        top:0,
        bottom:0
    }
})
import React, {Component} from 'react';
import {StyleSheet, View, TouchableOpacity, Image} from 'react-native';
import MyNavigationBar from './myNavigationBar';

export default class supermarket extends Component<Props> {

    renderButton(image){
        return (
            <TouchableOpacity>
                <Image source={image}  style={styles.myImage}/>
            </TouchableOpacity>
        )
    }

    render() {
        return (
            <View style={styles.container}>
                <MyNavigationBar
                    title='我是標題'
                    statusBar={{ //設定狀態列引數
                        backgroundColor:'#ff7888',
                        hidden:false,
                        translucent:false,
                    }}
                    leftButton={ //導航欄左方
                        this.renderButton(require("../../images/jiantou.png"))
                    }
                    rightButton={
                        this.renderButton(require("../../images/star.png"))
                    }
                />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
    },
    myImage:{
        width:22,
        height:22,
        margin:5
    }
});