From 9819681625ec7b48df22de14df55ca13eb94242b Mon Sep 17 00:00:00 2001 From: Hedger Wang Date: Tue, 21 Jun 2016 13:50:31 -0700 Subject: [PATCH] Pass the current and previous transition props to `render`, `onTransitionStart` and `onTransitionEnd`. Summary: This shall make it convenient to handle transition changes. Reviewed By: ericvicenti Differential Revision: D3442291 fbshipit-source-id: aee0ffe18ada40ef133484b4a4999f282c66c181 --- .../NavigationTransitioner.js | 101 ++++++++++++------ .../NavigationTypeDefinition.js | 15 ++- 2 files changed, 75 insertions(+), 41 deletions(-) diff --git a/Libraries/NavigationExperimental/NavigationTransitioner.js b/Libraries/NavigationExperimental/NavigationTransitioner.js index d563dfcdf..401bd33da 100644 --- a/Libraries/NavigationExperimental/NavigationTransitioner.js +++ b/Libraries/NavigationExperimental/NavigationTransitioner.js @@ -19,6 +19,8 @@ const React = require('React'); const StyleSheet = require('StyleSheet'); const View = require('View'); +const invariant = require('fbjs/lib/invariant'); + import type { NavigationAnimatedValue, NavigationLayout, @@ -33,7 +35,7 @@ type Props = { navigationState: NavigationState, onTransitionEnd: () => void, onTransitionStart: () => void, - render: (props: NavigationTransitionProps) => any, + render: (a: NavigationTransitionProps, b: ?NavigationTransitionProps) => any, style: any, }; @@ -56,9 +58,10 @@ function isSceneNotStale(scene: NavigationScene): boolean { } class NavigationTransitioner extends React.Component { - _onLayout: (event: any) => void; _onTransitionEnd: () => void; + _prevTransitionProps: ?NavigationTransitionProps; + _transitionProps: NavigationTransitionProps; props: Props; state: State; @@ -90,6 +93,9 @@ class NavigationTransitioner extends React.Component { progress: new Animated.Value(1), scenes: NavigationScenesReducer([], this.props.navigationState), }; + + this._prevTransitionProps = null; + this._transitionProps = buildTransitionProps(props, this.state); } componentWillMount(): void { @@ -108,15 +114,21 @@ class NavigationTransitioner extends React.Component { return; } + const nextState = { + ...this.state, + scenes: nextScenes, + }; + + this._prevTransitionProps = this._transitionProps; + this._transitionProps = buildTransitionProps(nextProps, nextState); + const { position, progress, - } = this.state; + } = nextState; // update scenes. - this.setState({ - scenes: nextScenes, - }); + this.setState(nextState); // get the transition spec. const transitionUserSpec = nextProps.configureTransition ? @@ -153,7 +165,10 @@ class NavigationTransitioner extends React.Component { } // play the transition. - nextProps.onTransitionStart && nextProps.onTransitionStart(); + nextProps.onTransitionStart && nextProps.onTransitionStart( + this._transitionProps, + this._prevTransitionProps, + ); Animated.parallel(animations).start(this._onTransitionEnd); } @@ -162,7 +177,7 @@ class NavigationTransitioner extends React.Component { - {this.props.render(this._buildTransitionProps())} + {this.props.render(this._transitionProps, this._prevTransitionProps)} ); } @@ -184,33 +199,55 @@ class NavigationTransitioner extends React.Component { } _onTransitionEnd(): void { + const prevTransitionProps = this._prevTransitionProps; + this._prevTransitionProps = null; + const scenes = this.state.scenes.filter(isSceneNotStale); - if (scenes.length !== this.state.scenes.length) { - this.setState({ scenes }); + this.setState({ scenes }); + + this.props.onTransitionEnd && this.props.onTransitionEnd( + this._transitionProps, + prevTransitionProps, + ); + } +} + +function buildTransitionProps( + props: Props, + state: State, +): NavigationTransitionProps { + const { + navigationState, + } = props; + + const { + layout, + position, + progress, + scenes, + } = state; + + return { + layout, + navigationState, + position, + progress, + scenes, + scene: findActiveScene(scenes, navigationState.index), + }; +} + +function findActiveScene( + scenes: Array, + index: number, +): NavigationScene { + for (let ii = 0, jj = scenes.length; ii < jj; ii++) { + const scene = scenes[ii]; + if (!scene.isStale && scene.index === index) { + return scene; } - this.props.onTransitionEnd && this.props.onTransitionEnd(); - } - - _buildTransitionProps(): NavigationTransitionProps { - const { - navigationState, - } = this.props; - - const { - layout, - position, - progress, - scenes, - } = this.state; - - return { - layout, - navigationState, - position, - progress, - scenes, - }; } + invariant(false, 'scenes must have an active scene'); } const styles = StyleSheet.create({ diff --git a/Libraries/NavigationExperimental/NavigationTypeDefinition.js b/Libraries/NavigationExperimental/NavigationTypeDefinition.js index 5e2977716..90a0359f4 100644 --- a/Libraries/NavigationExperimental/NavigationTypeDefinition.js +++ b/Libraries/NavigationExperimental/NavigationTypeDefinition.js @@ -64,19 +64,16 @@ export type NavigationTransitionProps = { // All the scenes of the transitioner. scenes: Array, -}; -export type NavigationSceneRendererProps = { - layout: NavigationLayout, - navigationState: NavigationState, - position: NavigationAnimatedValue, - progress: NavigationAnimatedValue, - scenes: Array, - - // The scene to render. + // The active scene, corresponding to the route at + // `navigationState.routes[navigationState.index]`. scene: NavigationScene, }; +// Similar to `NavigationTransitionProps`, except that the prop `scene` +// represents the scene for the renderer to render. +export type NavigationSceneRendererProps = NavigationTransitionProps; + export type NavigationPanPanHandlers = { onMoveShouldSetResponder: Function, onMoveShouldSetResponderCapture: Function,