React Native:自定義一個導航欄,改變狀態列背景,隱藏狀態列
阿新 • • 發佈:2018-11-15
設計開發過程中,導航欄都會有所不同,這時候使用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
}
});