Skip to content

Instantly share code, notes, and snippets.

@StevePotter
Created October 9, 2017 04:25
Show Gist options
  • Save StevePotter/da33bac31dcdb045dd37284e4ab623f9 to your computer and use it in GitHub Desktop.
Save StevePotter/da33bac31dcdb045dd37284e4ab623f9 to your computer and use it in GitHub Desktop.
/* @flow */
import React from 'react'
import { Header } from 'react-navigation'
import { View, StyleSheet } from 'react-native'
import NavBackButton from './NavBackButton'
import StatusBarSpacer from '../components/StatusBarSpacer'
const styles = StyleSheet.create({
root: {
flexDirection: 'column'
}
})
// TODO: eslint gives error about display-name despite it clearly being there. why?
/* eslint-disable react/display-name */
export default class NavHeader extends Header {
static displayName = 'NavHeader'
// copied from https://github.com/react-community/react-navigation/blob/30ca3c1f80617abc28fdd71f0b37d4f62b3e388a/src/views/Header.js#L114
// they make it nearly impossible to properly customize the button
_renderLeftComponent = (props:any) => {
const options = this.props.getScreenDetails(props.scene).options
// null is intentionally no left button
if (options.headerLeft === null) {
return null
}
// set to an actual component
if (options.headerLeft !== undefined) {
return (<View
onLayout={(e) => {
this.setState({
widths: {
...this.state.widths,
[props.scene.key + '-left']: e.nativeEvent.layout.width
}
})
}}
>
{options.headerLeft}
</View>)
}
if (props.scene.index === 0) {
return null
}
return (
<NavBackButton
icon={options.headerLeftIcon || 'whiteArrow'}
onPress={() => {
this.props.navigation.goBack(null)
}}
onLayout={(e) => {
this.setState({
widths: {
...this.state.widths,
[props.scene.key + '-left']: e.nativeEvent.layout.width
}
})
}}
/>
)
}
_renderRightComponent = (props:any) => {
// this is mostly copied from the source, except I surround
// the component in a View. That's because you can't just set onLayout on the
// headerRight component since it was already created.
const details = this.props.getScreenDetails(props.scene)
const { headerRight } = details.options
if (!headerRight) return null
return (<View
onLayout={(e) => {
this.setState({
widths: {
...this.state.widths,
[props.scene.key + '-right']: e.nativeEvent.layout.width
}
})
}}
>
{headerRight}
</View>)
}
// see https://github.com/react-community/react-navigation/issues/1728
_renderTitle(props: any, options: *): ?React.Element<*> {
// `view` contains the HeaderTitle component
// normally there is a hardcoded left/right from react-navigation that
// causes the trimming. that was circumvented by appending a left & right
// style, which take into account the width of the left and/or right nav buttons
const view = super._renderTitle(props, options)
const leftWidth = this.state.widths[props.scene.key + '-left'] || 0
const rightWidth = this.state.widths[props.scene.key + '-right'] || 0
const leftAndRight = Math.max(leftWidth, rightWidth)
if (view && view.props && view.props.style && view.props.style.length) {
view.props.style.push({ right: leftAndRight, left: leftAndRight })
}
return view
}
render() {
const header = super.render()
return (
<View style={styles.root}>
<StatusBarSpacer />
{header}
</View>
)
}
}
/* eslint-enable react/display-name */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment