From 81c62c5f41da2e34f0c0e19ca38843918c23c32b Mon Sep 17 00:00:00 2001 From: Hedger Wang Date: Tue, 19 Apr 2016 15:56:33 -0700 Subject: [PATCH] Fix initial scenes rendering. Summary:The initial layout used to render scenes does not contain the actual width and height measured and causes the issue as described at https://github.com/ericvicenti/navigation-rfc/issues/61 The fix is to update the layout and re-render scenes once layout is modified. Also scenes renderer should also consider the case that when the layout is not measured yet. Reviewed By: ericvicenti Differential Revision: D3162143 fb-gh-sync-id: 197574329d3849cad2a21e07e1bd5e800f74c3ea fbshipit-source-id: 197574329d3849cad2a21e07e1bd5e800f74c3ea --- .../NavigationCardStackStyleInterpolator.js | 30 +++++++++++++++++++ .../NavigationAnimatedView.js | 23 ++++++++------ .../NavigationPropTypes.js | 1 + .../NavigationTypeDefinition.js | 1 + 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackStyleInterpolator.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackStyleInterpolator.js index 0a25f6b1f863b5..fb5a7f4dd01dec 100644 --- a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackStyleInterpolator.js +++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackStyleInterpolator.js @@ -51,6 +51,28 @@ import type { * +------------+ */ +/** + * Render the initial style when the initial layout isn't measured yet. + */ +function forInitial(props: NavigationSceneRendererProps): Object { + const { + navigationState, + scene, + } = props; + + const focused = navigationState.index === scene.index; + const opacity = focused ? 1 : 0; + // If not focused, move the scene to the far away. + const translate = focused ? 0 : 1000000; + return { + opacity, + transform: [ + { translateX: translate }, + { translateY: translate }, + ], + }; +} + function forHorizontal(props: NavigationSceneRendererProps): Object { const { layout, @@ -58,6 +80,10 @@ function forHorizontal(props: NavigationSceneRendererProps): Object { scene, } = props; + if (!layout.isMeasured) { + return forInitial(props); + } + const index = scene.index; const inputRange = [index - 1, index, index + 1]; const width = layout.initWidth; @@ -95,6 +121,10 @@ function forVertical(props: NavigationSceneRendererProps): Object { scene, } = props; + if (!layout.isMeasured) { + return forInitial(props); + } + const index = scene.index; const inputRange = [index - 1, index, index + 1]; const height = layout.initHeight; diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js index 0ef8fb8471b052..efa2e4034dcf54 100644 --- a/Libraries/NavigationExperimental/NavigationAnimatedView.js +++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js @@ -39,6 +39,7 @@ type Props = { }; type State = { + layout: NavigationLayout, position: NavigationAnimatedValue, scenes: Array, }; @@ -61,7 +62,6 @@ function applyDefaultAnimation( class NavigationAnimatedView extends React.Component { - _layout: NavigationLayout; _onLayout: (event: any) => void; _onProgressChange: (data: {value: number}) => void; _positionListener: any; @@ -84,14 +84,18 @@ class NavigationAnimatedView constructor(props: Props, context: any) { super(props, context); - this._layout = { - initWidth: 0, + // The initial layout isn't measured. Measured layout will be only available + // when the component is mounted. + const layout = { + height: new Animated.Value(0), initHeight: 0, + initWidth: 0, + isMeasured: false, width: new Animated.Value(0), - height: new Animated.Value(0), }; this.state = { + layout, position: new Animated.Value(this.props.navigationState.index), scenes: NavigationScenesReducer([], this.props.navigationState), }; @@ -180,7 +184,7 @@ class NavigationAnimatedView } = this.state; return renderScene({ - layout: this._layout, + layout: this.state.layout, navigationState, onNavigate, position, @@ -203,7 +207,7 @@ class NavigationAnimatedView } = this.state; return renderOverlay({ - layout: this._layout, + layout: this.state.layout, navigationState, onNavigate, position, @@ -218,15 +222,16 @@ class NavigationAnimatedView const {height, width} = event.nativeEvent.layout; const layout = { - ...this._layout, + ...this.state.layout, initHeight: height, initWidth: width, + isMeasured: true, }; - this._layout = layout; - layout.height.setValue(height); layout.width.setValue(width); + + this.setState({ layout }); } } diff --git a/Libraries/NavigationExperimental/NavigationPropTypes.js b/Libraries/NavigationExperimental/NavigationPropTypes.js index 3355bec1f3f994..6a8a0488614b90 100644 --- a/Libraries/NavigationExperimental/NavigationPropTypes.js +++ b/Libraries/NavigationExperimental/NavigationPropTypes.js @@ -52,6 +52,7 @@ const layout = PropTypes.shape({ height: animatedValue, initHeight: PropTypes.number.isRequired, initWidth: PropTypes.number.isRequired, + isMeasured: PropTypes.bool.isRequired, width: animatedValue, }); diff --git a/Libraries/NavigationExperimental/NavigationTypeDefinition.js b/Libraries/NavigationExperimental/NavigationTypeDefinition.js index 687194e54e1ea4..08ccba47499630 100644 --- a/Libraries/NavigationExperimental/NavigationTypeDefinition.js +++ b/Libraries/NavigationExperimental/NavigationTypeDefinition.js @@ -37,6 +37,7 @@ export type NavigationLayout = { height: NavigationAnimatedValue, initHeight: number, initWidth: number, + isMeasured: boolean, width: NavigationAnimatedValue, };