mirror of
https://github.com/status-im/react-native.git
synced 2025-01-10 17:45:59 +00:00
68918e8773
Summary:This address the issue reported at https://github.com/facebook/react-native/issues/6579#issuecomment-200984628 NavigationView should have the same API as NavigationAnimatedView does except that NavigationView does not need the APIs for animation. This unify the API of our core components so that people can freely compose views with both NavigationAnimatedView or NavigationView. Reviewed By: fkgozali Differential Revision: D3096076 fb-gh-sync-id: 7536777a7d637da62a2636d750f9d91c5a0eb45f fbshipit-source-id: 7536777a7d637da62a2636d750f9d91c5a0eb45f
242 lines
5.5 KiB
JavaScript
242 lines
5.5 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
* @providesModule NavigationAnimatedView
|
|
* @flow
|
|
*/
|
|
'use strict';
|
|
|
|
const Animated = require('Animated');
|
|
const NavigationContainer = require('NavigationContainer');
|
|
const NavigationPropTypes = require('NavigationPropTypes');
|
|
const NavigationScenesReducer = require('NavigationScenesReducer');
|
|
const React = require('react-native');
|
|
const StyleSheet = require('StyleSheet');
|
|
const View = require('View');
|
|
|
|
import type {
|
|
NavigationActionCaller,
|
|
NavigationAnimatedValue,
|
|
NavigationAnimationSetter,
|
|
NavigationLayout,
|
|
NavigationParentState,
|
|
NavigationScene,
|
|
NavigationSceneRenderer,
|
|
} from 'NavigationTypeDefinition';
|
|
|
|
type Props = {
|
|
applyAnimation: NavigationAnimationSetter,
|
|
navigationState: NavigationParentState,
|
|
onNavigate: NavigationActionCaller,
|
|
renderOverlay: ?NavigationSceneRenderer,
|
|
renderScene: NavigationSceneRenderer,
|
|
style: any,
|
|
};
|
|
|
|
type State = {
|
|
position: NavigationAnimatedValue,
|
|
scenes: Array<NavigationScene>,
|
|
};
|
|
|
|
const {PropTypes} = React;
|
|
|
|
function applyDefaultAnimation(
|
|
position: NavigationAnimatedValue,
|
|
navigationState: NavigationParentState,
|
|
): void {
|
|
Animated.spring(
|
|
position,
|
|
{
|
|
bounciness: 0,
|
|
toValue: navigationState.index,
|
|
}
|
|
).start();
|
|
}
|
|
|
|
class NavigationAnimatedView
|
|
extends React.Component<any, Props, State> {
|
|
|
|
_layout: NavigationLayout;
|
|
_onLayout: (event: any) => void;
|
|
_onProgressChange: (data: {value: number}) => void;
|
|
_positionListener: any;
|
|
|
|
props: Props;
|
|
state: State;
|
|
|
|
static propTypes = {
|
|
applyAnimation: PropTypes.func,
|
|
navigationState: NavigationPropTypes.navigationState.isRequired,
|
|
onNavigate: PropTypes.func.isRequired,
|
|
renderOverlay: PropTypes.func,
|
|
renderScene: PropTypes.func.isRequired,
|
|
};
|
|
|
|
static defaultProps = {
|
|
applyAnimation: applyDefaultAnimation,
|
|
};
|
|
|
|
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: NavigationScenesReducer([], this.props.navigationState),
|
|
};
|
|
}
|
|
|
|
componentWillMount(): void {
|
|
this._onLayout = this._onLayout.bind(this);
|
|
this._onProgressChange = this._onProgressChange.bind(this);
|
|
}
|
|
|
|
componentDidMount(): void {
|
|
this._positionListener =
|
|
this.state.position.addListener(this._onProgressChange);
|
|
}
|
|
|
|
componentWillReceiveProps(nextProps: Props): void {
|
|
if (nextProps.navigationState !== this.props.navigationState) {
|
|
this.setState({
|
|
scenes: NavigationScenesReducer(
|
|
this.state.scenes,
|
|
nextProps.navigationState,
|
|
this.props.navigationState
|
|
),
|
|
});
|
|
}
|
|
}
|
|
|
|
componentDidUpdate(lastProps: Props): void {
|
|
if (lastProps.navigationState.index !== this.props.navigationState.index) {
|
|
this.props.applyAnimation(
|
|
this.state.position,
|
|
this.props.navigationState,
|
|
lastProps.navigationState
|
|
);
|
|
}
|
|
}
|
|
|
|
componentWillUnmount(): void {
|
|
this.state.position.removeListener(this._positionListener);
|
|
}
|
|
|
|
_onProgressChange(data: Object): void {
|
|
const delta = Math.abs(data.value - this.props.navigationState.index);
|
|
if (delta > Number.EPSILON) {
|
|
return;
|
|
}
|
|
|
|
const scenes = this.state.scenes.filter(scene => {
|
|
return !scene.isStale;
|
|
});
|
|
|
|
if (scenes.length !== this.state.scenes.length) {
|
|
this.setState({ scenes });
|
|
}
|
|
}
|
|
|
|
render(): ReactElement {
|
|
const overlay = this._renderOverlay();
|
|
const scenes = this._renderScenes();
|
|
return (
|
|
<View
|
|
onLayout={this._onLayout}
|
|
style={this.props.style}>
|
|
<View style={styles.scenes} key="scenes">
|
|
{scenes}
|
|
</View>
|
|
{overlay}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
_renderScenes(): Array<?ReactElement> {
|
|
return this.state.scenes.map(this._renderScene, this);
|
|
}
|
|
|
|
_renderScene(scene: NavigationScene): ?ReactElement {
|
|
const {
|
|
navigationState,
|
|
onNavigate,
|
|
renderScene,
|
|
} = this.props;
|
|
|
|
const {
|
|
position,
|
|
scenes,
|
|
} = this.state;
|
|
|
|
return renderScene({
|
|
layout: this._layout,
|
|
navigationState,
|
|
onNavigate,
|
|
position,
|
|
scene,
|
|
scenes,
|
|
});
|
|
}
|
|
|
|
_renderOverlay(): ?ReactElement {
|
|
if (this.props.renderOverlay) {
|
|
const {
|
|
navigationState,
|
|
onNavigate,
|
|
renderOverlay,
|
|
} = this.props;
|
|
|
|
const {
|
|
position,
|
|
scenes,
|
|
} = this.state;
|
|
|
|
return renderOverlay({
|
|
layout: this._layout,
|
|
navigationState,
|
|
onNavigate,
|
|
position,
|
|
scene: scenes[navigationState.index],
|
|
scenes,
|
|
});
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
scenes: {
|
|
flex: 1,
|
|
},
|
|
});
|
|
|
|
NavigationAnimatedView = NavigationContainer.create(NavigationAnimatedView);
|
|
|
|
module.exports = NavigationAnimatedView;
|