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
This commit is contained in:
Hedger Wang 2016-06-21 13:50:31 -07:00 committed by Facebook Github Bot 4
parent 6982f5aa24
commit c57bac4767
2 changed files with 75 additions and 41 deletions

View File

@ -19,6 +19,8 @@ const React = require('React');
const StyleSheet = require('StyleSheet'); const StyleSheet = require('StyleSheet');
const View = require('View'); const View = require('View');
const invariant = require('fbjs/lib/invariant');
import type { import type {
NavigationAnimatedValue, NavigationAnimatedValue,
NavigationLayout, NavigationLayout,
@ -33,7 +35,7 @@ type Props = {
navigationState: NavigationState, navigationState: NavigationState,
onTransitionEnd: () => void, onTransitionEnd: () => void,
onTransitionStart: () => void, onTransitionStart: () => void,
render: (props: NavigationTransitionProps) => any, render: (a: NavigationTransitionProps, b: ?NavigationTransitionProps) => any,
style: any, style: any,
}; };
@ -56,9 +58,10 @@ function isSceneNotStale(scene: NavigationScene): boolean {
} }
class NavigationTransitioner extends React.Component<any, Props, State> { class NavigationTransitioner extends React.Component<any, Props, State> {
_onLayout: (event: any) => void; _onLayout: (event: any) => void;
_onTransitionEnd: () => void; _onTransitionEnd: () => void;
_prevTransitionProps: ?NavigationTransitionProps;
_transitionProps: NavigationTransitionProps;
props: Props; props: Props;
state: State; state: State;
@ -90,6 +93,9 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
progress: new Animated.Value(1), progress: new Animated.Value(1),
scenes: NavigationScenesReducer([], this.props.navigationState), scenes: NavigationScenesReducer([], this.props.navigationState),
}; };
this._prevTransitionProps = null;
this._transitionProps = buildTransitionProps(props, this.state);
} }
componentWillMount(): void { componentWillMount(): void {
@ -108,15 +114,21 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
return; return;
} }
const nextState = {
...this.state,
scenes: nextScenes,
};
this._prevTransitionProps = this._transitionProps;
this._transitionProps = buildTransitionProps(nextProps, nextState);
const { const {
position, position,
progress, progress,
} = this.state; } = nextState;
// update scenes. // update scenes.
this.setState({ this.setState(nextState);
scenes: nextScenes,
});
// get the transition spec. // get the transition spec.
const transitionUserSpec = nextProps.configureTransition ? const transitionUserSpec = nextProps.configureTransition ?
@ -153,7 +165,10 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
} }
// play the transition. // play the transition.
nextProps.onTransitionStart && nextProps.onTransitionStart(); nextProps.onTransitionStart && nextProps.onTransitionStart(
this._transitionProps,
this._prevTransitionProps,
);
Animated.parallel(animations).start(this._onTransitionEnd); Animated.parallel(animations).start(this._onTransitionEnd);
} }
@ -162,7 +177,7 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
<View <View
onLayout={this._onLayout} onLayout={this._onLayout}
style={[styles.main, this.props.style]}> style={[styles.main, this.props.style]}>
{this.props.render(this._buildTransitionProps())} {this.props.render(this._transitionProps, this._prevTransitionProps)}
</View> </View>
); );
} }
@ -184,33 +199,55 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
} }
_onTransitionEnd(): void { _onTransitionEnd(): void {
const prevTransitionProps = this._prevTransitionProps;
this._prevTransitionProps = null;
const scenes = this.state.scenes.filter(isSceneNotStale); 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<NavigationScene>,
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({ const styles = StyleSheet.create({

View File

@ -64,19 +64,16 @@ export type NavigationTransitionProps = {
// All the scenes of the transitioner. // All the scenes of the transitioner.
scenes: Array<NavigationScene>, scenes: Array<NavigationScene>,
};
export type NavigationSceneRendererProps = { // The active scene, corresponding to the route at
layout: NavigationLayout, // `navigationState.routes[navigationState.index]`.
navigationState: NavigationState,
position: NavigationAnimatedValue,
progress: NavigationAnimatedValue,
scenes: Array<NavigationScene>,
// The scene to render.
scene: NavigationScene, 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 = { export type NavigationPanPanHandlers = {
onMoveShouldSetResponder: Function, onMoveShouldSetResponder: Function,
onMoveShouldSetResponderCapture: Function, onMoveShouldSetResponderCapture: Function,