diff --git a/src/views/Header.js b/src/views/Header.js index 38ae995..e0a34b6 100644 --- a/src/views/Header.js +++ b/src/views/Header.js @@ -58,6 +58,7 @@ type HeaderState = { const APPBAR_HEIGHT = Platform.OS === 'ios' ? 44 : 56; const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 : 0; +const TITLE_OFFSET = Platform.OS === 'ios' ? 70 : 40; class Header extends React.PureComponent { @@ -121,8 +122,23 @@ class Header extends React.PureComponent { const titleStyle = this._getHeaderTitleStyle(props.navigation); const color = this._getHeaderTintColor(props.navigation); const title = this._getHeaderTitle(props.navigation); + + // On iOS, width of left/right components depends on the calculated + // size of the title. + const onLayoutIOS = Platform.OS === 'ios' + ? (e: LayoutEvent) => { + this.setState({ + widths: { + ...this.state.widths, + [props.key]: e.nativeEvent.layout.width, + }, + }); + } + : undefined; + return ( {title} @@ -140,11 +156,15 @@ class Header extends React.PureComponent { state: props.scenes[props.scene.index - 1].route, }); const backButtonTitle = this._getBackButtonTitle(previousNavigation); + const width = this.state.widths[props.key] + ? (props.layout.initWidth - this.state.widths[props.key]) / 2 + : undefined; return ( ); }; @@ -161,9 +181,20 @@ class Header extends React.PureComponent { ); } - _renderTitle(props: NavigationSceneRendererProps): ?React.Element<*> { + _renderTitle(props: NavigationSceneRendererProps, options: *): ?React.Element<*> { + const style = {}; + + if (Platform.OS === 'android') { + if (!options.hasLeftComponent) { + style.left = 0; + } + if (!options.hasRightComponent) { + style.right = 0; + } + } + return this._renderSubView( - props, + { ...props, style }, 'title', this.props.renderTitleComponent, this._renderTitleComponent, @@ -216,36 +247,20 @@ class Header extends React.PureComponent { subView = defaultRenderer(subViewProps); } + if (subView === null) { + return null; + } + const pointerEvents = offset !== 0 || isStale ? 'none' : 'box-none'; - // On iOS, width of left/right components depends on the calculated - // size of the title. - const onLayoutIOS = Platform.OS === 'ios' && name === 'title' - ? (e: LayoutEvent) => { - this.setState({ - widths: { - ...this.state.widths, - [key]: e.nativeEvent.layout.width, - }, - }); - } - : undefined; - - const titleWidth = name === 'left' || name === 'right' - ? this.state.widths[key] - : undefined; - return ( @@ -257,15 +272,18 @@ class Header extends React.PureComponent { _renderHeader(props: NavigationSceneRendererProps): React.Element<*> { const left = this._renderLeft(props); const right = this._renderRight(props); - const title = this._renderTitle(props); + const title = this._renderTitle(props, { + hasLeftComponent: !!left, + hasRightComponent: !!right, + }); return ( - {left} {title} + {left} {right} ); @@ -289,7 +307,7 @@ class Header extends React.PureComponent { appBar = scenesProps.map(this._renderHeader, this); } else { appBar = this._renderHeader({ - ...this.props, + ...NavigationPropTypes.extractSceneRendererProps(this.props), position: new Animated.Value(this.props.scene.index), progress: new Animated.Value(0), }); @@ -329,19 +347,30 @@ const styles = StyleSheet.create({ }, item: { justifyContent: 'center', + alignItems: 'center', backgroundColor: 'transparent', }, - title: Platform.OS === 'android' - ? { - flex: 1, - alignItems: 'flex-start', - } - : {}, + title: { + bottom: 0, + left: TITLE_OFFSET, + right: TITLE_OFFSET, + top: 0, + position: 'absolute', + alignItems: Platform.OS === 'android' + ? 'flex-start' + : 'center', + }, left: { - alignItems: 'flex-start', + left: 0, + bottom: 0, + top: 0, + position: 'absolute', }, right: { - alignItems: 'flex-end', + right: 0, + bottom: 0, + top: 0, + position: 'absolute', }, }); diff --git a/src/views/HeaderBackButton.js b/src/views/HeaderBackButton.js index d375fdc..2bf8c04 100644 --- a/src/views/HeaderBackButton.js +++ b/src/views/HeaderBackButton.js @@ -19,6 +19,7 @@ type Props = { title?: ?string, tintColor?: ?string, truncatedTitle?: ?string, + width?: ?number, }; type DefaultProps = { @@ -27,7 +28,6 @@ type DefaultProps = { }; type State = { - containerWidth?: number, initialTextWidth?: number, }; @@ -37,6 +37,7 @@ class HeaderBackButton extends React.PureComponent { title: PropTypes.string, tintColor: PropTypes.string, truncatedTitle: PropTypes.string, + width: PropTypes.number, }; static defaultProps = { @@ -48,15 +49,6 @@ class HeaderBackButton extends React.PureComponent { state = {}; - _onContainerLayout = (e: LayoutEvent) => { - if (Platform.OS !== 'ios') { - return; - } - this.setState({ - containerWidth: e.nativeEvent.layout.width, - }); - }; - _onTextLayout = (e: LayoutEvent) => { if (this.state.initialTextWidth) { return; @@ -67,10 +59,10 @@ class HeaderBackButton extends React.PureComponent { }; render() { - const { onPress, title, tintColor, truncatedTitle } = this.props; + const { onPress, width, title, tintColor, truncatedTitle } = this.props; - const renderTruncated = this.state.containerWidth && this.state.initialTextWidth - ? this.state.containerWidth < this.state.initialTextWidth + const renderTruncated = this.state.initialTextWidth && width + ? this.state.initialTextWidth > width : false; return ( @@ -80,10 +72,7 @@ class HeaderBackButton extends React.PureComponent { style={styles.container} borderless > - + { /> {Platform.OS === 'ios' && title && (