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
This commit is contained in:
Hedger Wang 2016-03-08 10:56:58 -08:00 committed by Facebook Github Bot 6
parent e76fb68141
commit b5ae8a8ece
1 changed files with 81 additions and 62 deletions

View File

@ -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<any, Props, State> {
_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<NavigationScene>,
nextState: NavigationParentState,
lastState: ?NavigationParentState
): Array<NavigationScene> {
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 (
<View
onLayout={(e) => {
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()}
</View>
);
}
_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;