Change <Header /> layout back to absolute (#562)

This commit is contained in:
Mike Grabowski 2017-03-03 13:13:30 +01:00 committed by Satyajit Sahoo
parent bbab489a6a
commit e650f341e3
2 changed files with 69 additions and 52 deletions

View File

@ -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<void, HeaderProps, HeaderState> {
@ -121,8 +122,23 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
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 (
<HeaderTitle
onLayout={onLayoutIOS}
style={[color ? { color } : null, titleStyle]}
>
{title}
@ -140,11 +156,15 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
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 (
<HeaderBackButton
onPress={props.onNavigateBack}
tintColor={tintColor}
title={backButtonTitle}
width={width}
/>
);
};
@ -161,9 +181,20 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
);
}
_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<void, HeaderProps, HeaderState> {
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 (
<Animated.View
pointerEvents={pointerEvents}
onLayout={onLayoutIOS}
key={`${name}_${key}`}
style={[
titleWidth && {
width: (props.layout.initWidth - titleWidth) / 2,
},
styles.item,
styles[name],
props.style,
styleInterpolator(props),
]}
>
@ -257,15 +272,18 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
_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 (
<View
style={[StyleSheet.absoluteFill, styles.header]}
key={`scene_${props.scene.key}`}
>
{left}
{title}
{left}
{right}
</View>
);
@ -289,7 +307,7 @@ class Header extends React.PureComponent<void, HeaderProps, HeaderState> {
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',
},
});

View File

@ -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<DefaultProps, Props, State> {
title: PropTypes.string,
tintColor: PropTypes.string,
truncatedTitle: PropTypes.string,
width: PropTypes.number,
};
static defaultProps = {
@ -48,15 +49,6 @@ class HeaderBackButton extends React.PureComponent<DefaultProps, Props, State> {
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<DefaultProps, Props, State> {
};
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<DefaultProps, Props, State> {
style={styles.container}
borderless
>
<View
onLayout={this._onContainerLayout}
style={styles.container}
>
<View style={styles.container}>
<Image
style={[
styles.icon,
@ -94,7 +83,6 @@ class HeaderBackButton extends React.PureComponent<DefaultProps, Props, State> {
/>
{Platform.OS === 'ios' && title && (
<Text
ellipsizeMode="middle"
onLayout={this._onTextLayout}
style={[styles.title, { color: tintColor }]}
numberOfLines={1}