diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js index d24462648..cdf78b17a 100644 --- a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js +++ b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js @@ -265,21 +265,33 @@ class NavigationCompositionExample extends React.Component { } class ExampleMainView extends React.Component { + _renderScene: NavigationSceneRenderer; + + componentWillMount() { + this._renderScene = this._renderScene.bind(this); + } + render() { return ( ( - - )} + renderScene={this._renderScene} /> ); } + + _renderScene(props: NavigationSceneRendererProps): ReactElement { + const {scene} = props; + return ( + + ); + } + _handleNavigation(tabKey, action) { if (ExampleExitAction.match(action)) { this.props.onExampleExit(); @@ -288,6 +300,7 @@ class ExampleMainView extends React.Component { this.props.onNavigate(action); } } + ExampleMainView = NavigationContainer.create(ExampleMainView); const styles = StyleSheet.create({ diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js index ac5293373..e2635e267 100644 --- a/Libraries/NavigationExperimental/NavigationAnimatedView.js +++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js @@ -20,6 +20,7 @@ const StyleSheet = require('StyleSheet'); const View = require('View'); import type { + NavigationActionCaller, NavigationAnimatedValue, NavigationAnimationSetter, NavigationLayout, @@ -31,7 +32,7 @@ import type { type Props = { applyAnimation: NavigationAnimationSetter, navigationState: NavigationParentState, - onNavigate: (action: any) => void, + onNavigate: NavigationActionCaller, renderOverlay: ?NavigationSceneRenderer, renderScene: NavigationSceneRenderer, style: any, diff --git a/Libraries/NavigationExperimental/NavigationView.js b/Libraries/NavigationExperimental/NavigationView.js index 5789cfbf3..c79466d7a 100644 --- a/Libraries/NavigationExperimental/NavigationView.js +++ b/Libraries/NavigationExperimental/NavigationView.js @@ -11,51 +11,164 @@ */ 'use strict'; -var React = require('React'); -var NavigationContainer = require('NavigationContainer'); -var StyleSheet = require('StyleSheet'); -var View = require('View'); +const Animated = require('Animated'); +const NavigationContainer = require('NavigationContainer'); +const React = require('react-native'); +const StyleSheet = require('StyleSheet'); +const View = require('View'); +const NavigationScenesReducer = require('NavigationScenesReducer'); +const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); + +import type { + NavigationActionCaller, + NavigationAnimatedValue, + NavigationLayout, + NavigationParentState, + NavigationScene, + NavigationSceneRenderer, + NavigationSceneRendererProps, +} from 'NavigationTypeDefinition'; + +type Props = { + navigationState: NavigationParentState, + onNavigate: NavigationActionCaller, + renderScene: NavigationSceneRenderer, + style: any, +}; + +type State = { + scenes: Array, +}; + +const {PropTypes} = React; + +/** + * A simple view that will render a scene for the currently focused sub-state. + * The most common use-case is for tabs, where no transition is needed + */ +class NavigationView extends React.Component { + _layout: NavigationLayout; + _onLayout: (event: any) => void; + _position: NavigationAnimatedValue; + + props: Props; + state: State; + + static propTypes = { + navigationState: PropTypes.object.isRequired, + onNavigate: PropTypes.func.isRequired, + renderScene: PropTypes.func.isRequired, + }; + + constructor(props: Props, context: any) { + super(props, context); + + this._layout = { + initWidth: 0, + initHeight: 0, + width: new Animated.Value(0), + height: new Animated.Value(0), + }; + + const {navigationState} = this.props; + + this._position = new Animated.Value(navigationState.index); + + this.state = { + scenes: NavigationScenesReducer([], navigationState), + }; + } + + shouldComponentUpdate(nextProps: Props, nextState: State): boolean { + return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call( + this, + nextProps, + nextState + ); + } + + componentWillReceiveProps(nextProps: Props): void { + if (nextProps.navigationState !== this.props.navigationState) { + const {navigationState} = nextProps; + this.setState( + { + scenes: NavigationScenesReducer( + this.state.scenes, + navigationState, + null, // There will be no transtion. + ), + }, + () => { + this._position.setValue(navigationState.index); + }, + ); + } + } + + componentWillMount(): void { + this._onLayout = this._onLayout.bind(this); + } + + render(): ReactElement { + const { + navigationState, + onNavigate + } = this.props; + + const { + scenes, + } = this.state; + + const sceneProps = { + layout: this._layout, + navigationState: navigationState, + onNavigate: onNavigate, + position: this._position, + scene: scenes[navigationState.index], + scenes, + }; -var NavigationView = React.createClass({ - propTypes: { - // todo, figure out a propType for getK - navigationState: React.PropTypes.object.isRequired, - renderScene: React.PropTypes.func.isRequired, - }, - render: function() { return ( - {this.props.navigationState.children.map(this._renderScene)} + {this._renderScene(sceneProps)} ); - }, - _renderScene: function(route, index) { - var isSelected = index === this.props.navigationState.index; - return ( - - {this.props.renderScene(route, index)} - - ); - }, -}); + } -NavigationView = NavigationContainer.create(NavigationView); + _renderScene(props: NavigationSceneRendererProps): ?ReactElement { -var styles = StyleSheet.create({ - navView: { - position: 'absolute', + const child = this.props.renderScene(props); + if (child === null) { + return null; + } + return {child}; + } + + _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({ + scene: { + bottom: 0, left: 0, + position: 'absolute', right: 0, top: 0, - bottom: 0, }, }); -module.exports = NavigationView; +module.exports = NavigationContainer.create(NavigationView);