UNPKG

react-native-komect-uikit

Version:
207 lines (179 loc) 7.21 kB
// NavigationBar.js 'use strict'; import React, {Component} from 'react'; import PropTypes from 'prop-types'; import {StyleSheet, Platform, StatusBar, View, Text, Animated} from 'react-native'; import Theme from '../themes/Theme'; import NavigationTitle from './NavigationTitle'; import NavigationButton from './NavigationButton'; import NavigationLinkButton from './NavigationLinkButton'; import NavigationIconButton from './NavigationIconButton'; import NavigationBackButton from './NavigationBackButton'; export default class NavigationBar extends Component { static propTypes = { ...View.propTypes, type: PropTypes.oneOf(['auto', 'ios', 'android']), title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), titleStyle: Text.propTypes.style, leftView: PropTypes.element, rightView: PropTypes.element, tintColor: PropTypes.string, //bar tint color, default tint color leftView and rightView hidden: PropTypes.bool, //bar hidden animated: PropTypes.bool, //hide or show bar with animation statusBarStyle: PropTypes.oneOf(['default', 'light-content']), //status bar style (iOS only) statusBarColor: PropTypes.string, //status bar color, default: style.backgroundColor statusBarHidden: PropTypes.bool, //status bar hidden statusBarInsets: PropTypes.bool, //auto add space for iOS status bar }; static defaultProps = { ...View.defaultProps, type: 'ios', hidden: false, animated: true, statusBarInsets: true, }; static childContextTypes = { tintColor: PropTypes.string, }; static Title = NavigationTitle; static Button = NavigationButton; static LinkButton = NavigationLinkButton; static IconButton = NavigationIconButton; static BackButton = NavigationBackButton; constructor(props) { super(props); this.state = { leftViewWidth: 0, rightViewWidth: 0, barTop: new Animated.Value(props.hidden ? -64 : 0), barOpacity: new Animated.Value(props.hidden ? 0 : 1), }; } componentWillReceiveProps(nextProps) { if (nextProps.hidden != this.props.hidden) { this.checkBarHidden(nextProps.hidden, nextProps.animated); } } getChildContext() { return {tintColor: this.props.tintColor}; } buildProps() { let {style, type, title, titleStyle, tintColor, hidden, animated, statusBarColor, statusBarStyle, statusBarInsets, ...others} = this.props; //build style let justifyContent, titleTextAlign; switch (type === 'auto' ? Platform.OS : type) { case 'ios': justifyContent = 'space-between'; titleTextAlign = 'center'; break; case 'android': justifyContent = 'flex-end'; titleTextAlign = 'left'; break; } style = [{ backgroundColor: Theme.navColor, position: 'absolute', left: 0, right: 0, height: statusBarInsets && Platform.OS === 'ios' ? 64 : 44, paddingTop: statusBarInsets && Platform.OS === 'ios' ? 20 : 0, paddingLeft: 4, paddingRight: 4, borderBottomWidth: Theme.navSeparatorLineWidth, borderBottomColor: Theme.navSeparatorColor, flexDirection: 'row', alignItems: 'center', justifyContent: justifyContent, }].concat(style).concat({ top: this.state.barTop, //hidden or shown }); let fs = StyleSheet.flatten(style); //build tintColor if (!tintColor) tintColor = Theme.navTintColor; //build statusBarColor and statusBarStyle if (!statusBarColor) statusBarColor = fs.backgroundColor; if (!statusBarStyle) statusBarStyle = Theme.navStatusBarStyle ? Theme.navStatusBarStyle : 'default'; //build titleViewStyle let {leftViewWidth, rightViewWidth} = this.state; let barPaddingLeft = fs.paddingLeft ? fs.paddingLeft : (fs.padding ? fs.padding : 0); let barPaddingRight = fs.paddingRight ? fs.paddingRight : (fs.padding ? fs.padding : 0); let paddingLeft, paddingRight; switch (type === 'auto' ? Platform.OS : type) { case 'ios': let paddingLeftRight = Math.max(leftViewWidth + barPaddingLeft, rightViewWidth + barPaddingRight); paddingLeft = paddingLeftRight; paddingRight = paddingLeftRight; break; case 'android': paddingLeft = barPaddingLeft; paddingRight = leftViewWidth + rightViewWidth + barPaddingRight; break; } let titleViewStyle = { position: 'absolute', top: statusBarInsets && Platform.OS === 'ios' ? 20 : 0, left: 0, right: 0, height: 44, paddingLeft: paddingLeft, paddingRight: paddingRight, opacity: this.state.barOpacity, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }; //build leftView and rightView style let leftRightViewStyle = {opacity: this.state.barOpacity}; //convert string title to NavigationBar.Title if (typeof title === 'string') { title = <this.constructor.Title style={{textAlign: titleTextAlign, color: Theme.navTitleColor}} text={title} />; } this.props = {style, type, title, titleStyle, tintColor, titleViewStyle, leftRightViewStyle, hidden, animated, statusBarColor, statusBarStyle, statusBarInsets, ...others}; } checkBarHidden(hidden, animated) { let {barTop, barOpacity} = this.state; let barTopValue = hidden ? -this.barHeight : 0; let barOpacityValue = hidden ? 0 : 1; if (barTop._value != barTopValue || barOpacity._value != barOpacityValue) { if (animated) { Animated.parallel([ Animated.spring(barTop, {toValue: barTopValue, friction: 9}), Animated.spring(barOpacity, {toValue: barOpacityValue, friction: 9}), ]).start(); } else { barTop.setValue(barTopValue); barOpacity.setValue(barOpacityValue); } } } onLayout(e) { if (e.nativeEvent.layout.height != this.barHeight) { this.barHeight = e.nativeEvent.layout.height; this.checkBarHidden(this.props.hidden, this.props.animated); } this.props.onLayout && this.props.onLayout(e); } onLeftViewLayout(e) { if (e.nativeEvent.layout.width != this.state.leftViewWidth) { this.setState({leftViewWidth: e.nativeEvent.layout.width}); } } onRightViewLayout(e) { if (e.nativeEvent.layout.width != this.state.rightViewWidth) { this.setState({rightViewWidth: e.nativeEvent.layout.width}); } } render() { this.buildProps(); let {style, animated, statusBarStyle, statusBarColor, statusBarHidden, title, titleViewStyle, leftRightViewStyle, leftView, rightView, ...others} = this.props; return ( <Animated.View style={style} {...others} onLayout={e => this.onLayout(e)}> <StatusBar backgroundColor={statusBarColor} barStyle={statusBarStyle} animated={animated} hidden={statusBarHidden} /> <Animated.View style={titleViewStyle}>{title}</Animated.View> <Animated.View style={leftRightViewStyle} onLayout={e => this.onLeftViewLayout(e)}>{leftView}</Animated.View> <Animated.View style={leftRightViewStyle} onLayout={e => this.onRightViewLayout(e)}>{rightView}</Animated.View> </Animated.View> ); } }