From b5ae8a8ece5d81a099de9db6cf4f192a60ce6b03 Mon Sep 17 00:00:00 2001 From: Hedger Wang Date: Tue, 8 Mar 2016 10:56:58 -0800 Subject: [PATCH] Clean up NavigationAnimatedView Summary:- Add flow type checks. - Fix code styles. - Improve the logics to update `this.state.scenes`. - Improve the logics to pass the layout. Reviewed By: ericvicenti Differential Revision: D3022107 fb-gh-sync-id: 23f4ed22db797f68bde0ba4f3cdd123701934fc3 shipit-source-id: 23f4ed22db797f68bde0ba4f3cdd123701934fc3 --- .../NavigationAnimatedView.js | 143 ++++++++++-------- 1 file changed, 81 insertions(+), 62 deletions(-) diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js index 845b4a7a0..c77569a77 100644 --- a/Libraries/NavigationExperimental/NavigationAnimatedView.js +++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js @@ -21,9 +21,11 @@ const View = require('View'); import type { NavigationAnimatedValue, NavigationAnimationSetter, + NavigationLayout, NavigationParentState, NavigationScene, NavigationSceneRenderer, + NavigationState, } from 'NavigationTypeDefinition'; /** @@ -102,71 +104,87 @@ const defaultProps = { class NavigationAnimatedView extends React.Component { - _animatedHeight: Animated.Value; - _animatedWidth: Animated.Value; - _lastHeight: number; - _lastWidth: number; + _layout: NavigationLayout; + _onLayout: (event: any) => void; + _onProgressChange: (data: {value: number}) => void; _positionListener: any; props: Props; state: State; - constructor(props) { - super(props); - this._lastWidth = 0; - this._lastHeight = 0; - this._animatedHeight = new Animated.Value(this._lastHeight); - this._animatedWidth = new Animated.Value(this._lastWidth); + constructor(props: Props, context: any) { + super(props, context); + + this._layout = { + initWidth: 0, + initHeight: 0, + width: new Animated.Value(0), + height: new Animated.Value(0), + }; this.state = { position: new Animated.Value(this.props.navigationState.index), - scenes: [], + scenes: this._reduceScenes([], this.props.navigationState), }; } - componentWillMount() { - this.setState({ - scenes: this._reduceScenes(this.state.scenes, this.props.navigationState), - }); + + componentWillMount(): void { + this._onLayout = this._onLayout.bind(this); + this._onProgressChange = this._onProgressChange.bind(this); } - componentDidMount() { - this._positionListener = this.state.position.addListener(this._onProgressChange.bind(this)); + + componentDidMount(): void { + this._positionListener = + this.state.position.addListener(this._onProgressChange); } - componentWillReceiveProps(nextProps) { + + componentWillReceiveProps(nextProps: Props): void { if (nextProps.navigationState !== this.props.navigationState) { this.setState({ - scenes: this._reduceScenes(this.state.scenes, nextProps.navigationState, this.props.navigationState), + scenes: this._reduceScenes( + this.state.scenes, + nextProps.navigationState, + this.props.navigationState + ), }); } } - componentDidUpdate(lastProps) { - if (lastProps.navigationState.index !== this.props.navigationState.index && this.props.setTiming) { - this.props.setTiming(this.state.position, this.props.navigationState, lastProps.navigationState); + + componentDidUpdate(lastProps: Props): void { + if (lastProps.navigationState.index !== this.props.navigationState.index) { + this.props.setTiming( + this.state.position, + this.props.navigationState, + lastProps.navigationState + ); } } - componentWillUnmount() { - if (this._positionListener) { - this.state.position.removeListener(this._positionListener); - this._positionListener = null; - } + + componentWillUnmount(): void { + this.state.position.removeListener(this._positionListener); } + _onProgressChange(data: Object): void { - if (Math.abs(data.value - this.props.navigationState.index) > Number.EPSILON) { + const delta = Math.abs(data.value - this.props.navigationState.index); + if (delta > Number.EPSILON) { return; } - this.state.scenes.forEach((scene, index) => { - if (scene.isStale) { - const scenes = this.state.scenes.slice(); - scenes.splice(index, 1); - this.setState({ scenes, }); - } + + const scenes = this.state.scenes.filter(scene => { + return !scene.isStale; }); + + if (scenes.length !== this.state.scenes.length) { + this.setState({ scenes }); + } } + _reduceScenes( scenes: Array, nextState: NavigationParentState, lastState: ?NavigationParentState ): Array { - let nextScenes = nextState.children.map((child, index) => { + const nextScenes = nextState.children.map((child, index) => { return { index, isStale: false, @@ -175,8 +193,11 @@ class NavigationAnimatedView }); if (lastState) { - lastState.children.forEach((child, index) => { - if (!NavigationStateUtils.get(nextState, child.key) && index !== nextState.index) { + lastState.children.forEach((child: NavigationState, index: number) => { + if ( + !NavigationStateUtils.get(nextState, child.key) && + index !== nextState.index + ) { nextScenes.push({ index, isStale: true, @@ -186,38 +207,21 @@ class NavigationAnimatedView }); } - nextScenes = nextScenes.sort(compareScenes); - - return nextScenes; + return nextScenes.sort(compareScenes); } - render() { + + render(): ReactElement { return ( { - const {height, width} = e.nativeEvent.layout; - this._animatedHeight && - this._animatedHeight.setValue(height); - this._animatedWidth && - this._animatedWidth.setValue(width); - this._lastHeight = height; - this._lastWidth = width; - }} + onLayout={this._onLayout} style={this.props.style}> {this.state.scenes.map(this._renderScene, this)} {this._renderOverlay()} ); } - _getLayout() { - return { - height: this._animatedHeight, - width: this._animatedWidth, - initWidth: this._lastWidth, - initHeight: this._lastHeight, - }; - } - _renderScene(scene: NavigationScene) { + _renderScene(scene: NavigationScene): ?ReactElement { const { navigationState, onNavigate, @@ -230,7 +234,7 @@ class NavigationAnimatedView } = this.state; return renderScene({ - layout: this._getLayout(), + layout: this._layout, navigationState, onNavigate, position, @@ -239,7 +243,7 @@ class NavigationAnimatedView }); } - _renderOverlay() { + _renderOverlay(): ?ReactElement { if (this.props.renderOverlay) { const { navigationState, @@ -253,7 +257,7 @@ class NavigationAnimatedView } = this.state; return renderOverlay({ - layout: this._getLayout(), + layout: this._layout, navigationState, onNavigate, position, @@ -263,6 +267,21 @@ class NavigationAnimatedView } return null; } + + _onLayout(event: any): void { + const {height, width} = event.nativeEvent.layout; + + const layout = { + ...this._layout, + initHeight: height, + initWidth: width, + }; + + this._layout = layout; + + layout.height.setValue(height); + layout.width.setValue(width); + } } NavigationAnimatedView.propTypes = propTypes;