ReactNative 自定義標題欄 ReactNative 自定義導航欄
阿新 • • 發佈:2019-01-23
/**
* Created by 李卓原 on 2018/7/6.
* email: zhuoyuan93@gmail.com
*
*/
import React from 'react';
import {
Text,
StyleSheet,
View,
Image,
ImageBackground,
TouchableOpacity,
Platform,
StatusBar,
ViewPropTypes
} from 'react-native';
//ScreenUtil 為螢幕尺寸適配的工具類
import * as ScreenUtil from "../utils/ScreenUtil" ;
import PropTypes from 'prop-types';
const NAV_BAR_HEIGHT_ANDROID = 50;
const NAV_BAR_HEIGHT_IOS = 44;
const StatusBarShape = {
barStyle: PropTypes.oneOf(['light-content', 'default', 'dark-content']),
hidden: PropTypes.bool,
backgroundColor: PropTypes.string,
};
class NavigationBar extends React.Component {
static propTypes = {
statusBar: PropTypes.shape(StatusBarShape),
showBackgroundIMG: PropTypes.bool,
style: ViewPropTypes.style,
title: PropTypes.string,
titleView: PropTypes.element,
titleLayoutStyle: ViewPropTypes.style,
showLeft: PropTypes.bool,
leftText: PropTypes.string,
leftTextStyle: ViewPropTypes.style,
showleftImg: PropTypes.bool,
leftButton: PropTypes.element,
showRight: PropTypes.bool,
rightText: PropTypes.string,
rightTextStyle: ViewPropTypes.style,
rightButton: PropTypes.element,
};
static defaultProps = {
statusBar: {
barStyle: 'default' ,
hidden: false,
},
showLeft: true,
showleftImg: true, //是否顯示返回箭頭
leftText: '', //返回鍵位置的文字
showRight: false,
rightText: '更多',
showBackgroundIMG: true //是否有背景圖片
};
constructor(props) {
super(props);
}
render() {
let leftButton = this._renderLeft();
let rightButton = this._renderRight();
let statusBar = <View>
<StatusBar {...this.props.statusBar}/></View>;
let titleView = this.props.titleView ? this.props.titleView :
<Text style={[styles.titleStyle, this.props.titleLayoutStyle]}>{this.props.title}</Text>;
let content = <View style={styles.content}>
{leftButton}
<View style={styles.titleView}>{titleView}</View>
{rightButton}
</View>;
return (
<ImageBackground source={this.props.showBackgroundIMG ? require('IMG/app_bar.png') : null}
style={[styles.container, this.props.style]}>
{statusBar}
{content}
</ImageBackground>
)
}
_renderLeft() {
let {leftButton, leftTextStyle, showLeft, navigation, onLeftClick, leftText, showleftImg} = this.props;
if (!showLeft) {
return null;
}
if (leftButton == null) {
return (
<TouchableOpacity onPress={() => {
if (onLeftClick) {
onLeftClick();
} else {
if (navigation) navigation.goBack()
}
}}>
<View style={styles.leftContainer}>
{
showleftImg ?
<Image source={require('IMG/back.png')}
style={{
width: ScreenUtil.scaleSize(25),
height: ScreenUtil.scaleSize(25)
}}/>
: null
}
<Text style={[styles.leftRightStyle, leftTextStyle]}>{leftText}</Text>
</View>
</TouchableOpacity>)
}
return leftButton;
}
_renderRight() {
let {rightButton, rightTextStyle, showRight, onRightClick, rightText} = this.props;
if (!showRight) {
return null;
}
if (rightButton == null) {
return (
<TouchableOpacity onPress={() => {
if (onRightClick) {
onRightClick()
}
}}>
<View>
<Text style={[styles.leftRightStyle, rightTextStyle]}>{rightText}</Text>
</View>
</TouchableOpacity>)
}
return rightButton;
}
}
/**
* //selector:這是你自己編寫的一個函式。這個函式聲明瞭你的元件需要整個 store 中的哪一部分資料作為自己的 props
* 如果用不到redux這個方法可以刪除
* @param store
* @returns {{color: *}}
*/
function changeColor(store) {
return {
color: store.changeColorReducer.color
}
}
const styles = StyleSheet.create({
container: {
//backgroundColor:'green',
width: ScreenUtil.screenW,
height: ScreenUtil.scaleSize(58),
justifyContent: 'center',
},
content: {
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center',
height: Platform.OS === 'ios' ? NAV_BAR_HEIGHT_IOS : NAV_BAR_HEIGHT_ANDROID,
},
titleView: {
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
left: 40,
right: 40,
top: 0,
bottom: 0,
},
titleStyle: {
fontSize: ScreenUtil.setSpText(18),
color: 'white'
},
leftRightStyle: {
color: 'white',
fontSize: ScreenUtil.setSpText(14)
},
leftContainer: {
marginLeft: ScreenUtil.scaleSize(17),
flexDirection: 'row',
alignItems: 'center'
}
});
// 包裝 component ,注入 dispatch 和 state 到其預設的 connect(selector)(App) 中;
/**
* 把這個元件用connect包裹住就能拿到store。
注意export default已經拿到下面來了,上面的class前面的匯出要刪掉
用redux的話需要第一種方法匯出,已註釋掉
*/
//export default connect(changeColor)(withNavigation(NavigationBar));
//用不到redux推薦在定義類的時候直接匯出,類定義為 export default class ...
//當這個元件拿不到this.props.navigation時,可使用withNavigation
//withNavigation是一個更高階的元件,它將導航道具傳遞給一個包裝元件。
//當您無法直接將導航道具傳遞到元件時,或者在深度巢狀子節點的情況下不希望傳遞導航道具時,它非常有用。
//匯出方式:export default withNavigation(NavigationBar);
export default NavigationBar;
在頁面使用:
常規頁面插入
render() {
return (
<View style={{flex: 1}}>
{this._renderNav()}
...
</View>
)
}
_renderNav() {
return (
<NavigationBar
title={'Main'}
//showLeft={false}
onLeftClick={()=>{
alert('a')
}}
leftButton={()=><View><Text>自定義左側按鈕</Text></View>}
statusBar={{
barStyle: 'dark-content',
backgroundColor: 'white',
hidden: false,//true則隱藏
}}
/>
)
}
配合ReactNavigation使用
const RootStack = createStackNavigator({
TaskList: {screen: TaskListPage},
TaskDetails: {screen: TaskDetailsPage}
}, {
navigationOptions: ({navigation}) => ({
header: <NavigationBar title={navigation.state.routeName}
showLeft={navigation.state.routeName !== 'TaskList'}
navigation={navigation}
/>
})
});
屬性:
Prop | Type | Default | Description |
---|---|---|---|
style | ViewPropTypes.style | - | 標題欄的樣式 |
showBackgroundIMG | bool | true | 背景為一個圖片 |
title | string | - | 標題使用的字串 |
titleLayoutStyle | ViewPropTypes.style | - | 標題文字的樣式 |
titleView | PropTypes.element | - | 替換標題文字的元件 |
leftButton | PropTypes.element | - | 自定義左側按鈕 |
leftText | string | - | 左側返回按鈕的文字 |
leftTextStyle | ViewPropTypes.style | - | 替換標題文字的元件 |
showLeft | bool | true | 是否顯示返回按鈕 |
leftImg | source的引數 | ImageSourcePropType | 左側圖片的地址 |
showleftImg | bool | true | 是否顯示標題的後退按鈕,需自行替換成其他Image |
showLeft | bool | true | 是否顯示返回按鈕 |
onLeftClick | func | this.props.navigation.goBack() | 左側按鈕的點選事件(預設為ReactNavigation的goback) |
showRight | bool | false | 是否顯示右側按鈕 |
rightText | string | 更多 | 右側按鈕的文字 |
rightImg | source的引數 | ImageSourcePropType | 右側圖片的地址,預設不傳則不顯示 |
rightTextStyle | ViewPropTypes.style | - | 是否顯示返回按鈕 |
rightButton | PropTypes.element | - | 自定義右側按鈕 |
onRightClick | PropTypes.func | - | 右側按鈕的點選事件 |
statusBar | { barStyle: PropTypes.oneOf([‘light-content’, ‘default’, ‘dark-content’]), hidden: PropTypes.bool, backgroundColor: PropTypes.string,} | { barStyle: ‘default’, hidden: false,} | 自定義狀態列 |
可以自己傳入statusBar,預設值為:
statusBar: {
barStyle: 'default',
hidden: false, //true則隱藏statusBar
}
樣式大概如此,顏色可以自己定義,
左側按鈕,中間文字,和右側按鈕都可以自己傳入一個自己寫的佈局。
後續會完善功能和方法。