Implements `renderHeader` for legacy navigator.
Reviewed By: ericvicenti Differential Revision: D3029188 fb-gh-sync-id: 6f0b91244bc0d0e5eee0e610764a39adaaffe001 shipit-source-id: 6f0b91244bc0d0e5eee0e610764a39adaaffe001
This commit is contained in:
parent
26b2aa91b6
commit
3833c1b751
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||
*
|
||||
* Facebook, Inc. ("Facebook") owns all right, title and interest, including
|
||||
* all intellectual property and other proprietary rights, in and to the React
|
||||
* Native CustomComponents software (the "Software"). Subject to your
|
||||
* compliance with these terms, you are hereby granted a non-exclusive,
|
||||
* worldwide, royalty-free copyright license to (1) use and copy the Software;
|
||||
* and (2) reproduce and distribute the Software as part of your own software
|
||||
* ("Your Software"). Facebook reserves all rights not expressly granted to
|
||||
* you in this license agreement.
|
||||
*
|
||||
* THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
|
||||
* EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @providesModule NavigationAnimatedValueSubscription
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
import type {
|
||||
NavigationAnimatedValue
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
class NavigationAnimatedValueSubscription {
|
||||
_value: NavigationAnimatedValue;
|
||||
_token: string;
|
||||
|
||||
constructor(value: NavigationAnimatedValue, callback: Function) {
|
||||
this._value = value;
|
||||
this._token = value.addListener(callback);
|
||||
}
|
||||
|
||||
remove(): void {
|
||||
this._value.removeListener(this._token);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = NavigationAnimatedValueSubscription;
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
const NavigationAnimatedValueSubscription = require('NavigationAnimatedValueSubscription');
|
||||
const NavigationAnimatedView = require('NavigationAnimatedView');
|
||||
const NavigationCard = require('NavigationCard');
|
||||
const NavigationContext = require('NavigationContext');
|
||||
|
@ -45,16 +46,22 @@ import type {
|
|||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
type State = any;
|
||||
|
||||
type Props = {
|
||||
configureScene: any,
|
||||
initialRoute: any,
|
||||
initialRouteStack: any,
|
||||
renderScene: any,
|
||||
navigationBar: any,
|
||||
navigationBarNavigator: any,
|
||||
renderScene: any,
|
||||
style: any,
|
||||
};
|
||||
|
||||
type State = {
|
||||
presentedIndex: number,
|
||||
routeStack: Array<any>,
|
||||
};
|
||||
|
||||
function getConfigPopDirection(config: any): ?string {
|
||||
if (config && config.gestures && config.gestures.pop) {
|
||||
const direction = config.gestures.pop.direction;
|
||||
|
@ -75,15 +82,24 @@ const RouteStack = NavigationLegacyNavigatorRouteStack;
|
|||
* `NavigationAnimatedView`...etc.
|
||||
*/
|
||||
class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
||||
static BreadcrumbNavigationBar;
|
||||
static BreadcrumbNavigationBar: any;
|
||||
static NavigationBar: any;
|
||||
static SceneConfigs: any;
|
||||
|
||||
_key: string;
|
||||
_navigationBarRef: any;
|
||||
_onNavigationBarRef: (ref: any) => void;
|
||||
_onPositionChange: (data: {value: number}) => void;
|
||||
_positionListener: ?NavigationAnimatedValueSubscription;
|
||||
_previousStack: NavigationLegacyNavigatorRouteStack;
|
||||
_renderCard: NavigationSceneRenderer;
|
||||
_renderHeader: NavigationSceneRenderer;
|
||||
_renderScene: NavigationSceneRenderer;
|
||||
_stack: NavigationLegacyNavigatorRouteStack;
|
||||
|
||||
navigationContext: NavigationContext;
|
||||
props: Props;
|
||||
state: State;
|
||||
|
||||
constructor(props: Props, context: any) {
|
||||
super(props, context);
|
||||
|
@ -91,14 +107,22 @@ class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
|||
this.navigationContext = new NavigationContext();
|
||||
|
||||
const stack = this._getInitialRouteStack();
|
||||
|
||||
// Unfortunately, due to historical reasons, the `state` has been exposed
|
||||
// as public members of the navigator, therefore we'd keep private state
|
||||
// as private members.
|
||||
this._key = guid();
|
||||
this._previousStack = stack;
|
||||
this._stack = stack;
|
||||
|
||||
this.state = {
|
||||
key: guid(),
|
||||
stack,
|
||||
routeStack: stack.toArray(),
|
||||
presentedIndex: stack.index,
|
||||
};
|
||||
}
|
||||
|
||||
jumpTo(route: any): void {
|
||||
const index = this.state.stack.indexOf(route);
|
||||
const index = this._stack.indexOf(route);
|
||||
invariant(
|
||||
index > -1,
|
||||
'Cannot jump to route that is not in the route stack'
|
||||
|
@ -107,26 +131,26 @@ class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
|||
}
|
||||
|
||||
jumpForward(): void {
|
||||
this._jumpToIndex(this.state.stack.index + 1);
|
||||
this._jumpToIndex(this._stack.index + 1);
|
||||
}
|
||||
|
||||
jumpBack(): void {
|
||||
this._jumpToIndex(this.state.stack.index - 1);
|
||||
this._jumpToIndex(this._stack.index - 1);
|
||||
}
|
||||
|
||||
push(route: any): void {
|
||||
this.setState({stack: this.state.stack.push(route)});
|
||||
this._applyStack(this._stack.push(route));
|
||||
}
|
||||
|
||||
pop(): void {
|
||||
const {stack} = this.state;
|
||||
const stack = this._stack;
|
||||
if (stack.size > 1) {
|
||||
this.setState({stack: stack.pop()});
|
||||
this._applyStack(stack.pop());
|
||||
}
|
||||
}
|
||||
|
||||
replaceAtIndex(route: any, index: number): void {
|
||||
const {stack} = this.state;
|
||||
const stack = this._stack;
|
||||
|
||||
if (index < 0) {
|
||||
index += stack.size;
|
||||
|
@ -137,65 +161,63 @@ class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
|||
return;
|
||||
}
|
||||
|
||||
this.setState({stack: stack.replaceAtIndex(index, route)});
|
||||
this._applyStack(stack.replaceAtIndex(index, route));
|
||||
}
|
||||
|
||||
replace(route: any): void {
|
||||
this.replaceAtIndex(route, this.state.stack.index);
|
||||
this.replaceAtIndex(route, this._stack.index);
|
||||
}
|
||||
|
||||
replacePrevious(route: any): void {
|
||||
this.replaceAtIndex(route, this.state.stack.index - 1);
|
||||
this.replaceAtIndex(route, this._stack.index - 1);
|
||||
}
|
||||
|
||||
popToTop(): void {
|
||||
this.setState({stack: this.state.stack.slice(0, 1)});
|
||||
this._applyStack(this._stack.slice(0, 1));
|
||||
}
|
||||
|
||||
popToRoute(route: any): void {
|
||||
const {stack} = this.state;
|
||||
const stack = this._stack;
|
||||
const nextIndex = stack.indexOf(route);
|
||||
invariant(
|
||||
nextIndex > -1,
|
||||
'Calling popToRoute for a route that doesn\'t exist!'
|
||||
);
|
||||
this.setState({stack: stack.slice(0, nextIndex + 1)});
|
||||
this._applyStack(stack.slice(0, nextIndex + 1));
|
||||
}
|
||||
|
||||
replacePreviousAndPop(route: any): void {
|
||||
const {stack} = this.state;
|
||||
const stack = this._stack;
|
||||
const nextIndex = stack.index - 1;
|
||||
if (nextIndex < 0) {
|
||||
return;
|
||||
}
|
||||
this.setState({stack: stack.replaceAtIndex(nextIndex, route).pop()});
|
||||
this._applyStack(stack.replaceAtIndex(nextIndex, route).pop());
|
||||
}
|
||||
|
||||
resetTo(route: any): void {
|
||||
invariant(!!route, 'Must supply route');
|
||||
this.setState({stack: this.state.stack.slice(0).replaceAtIndex(0, route)});
|
||||
this._applyStack(this._stack.slice(0).replaceAtIndex(0, route));
|
||||
}
|
||||
|
||||
immediatelyResetRouteStack(routes: Array<any>): void {
|
||||
const index = routes.length - 1;
|
||||
const stack = new RouteStack(index, routes);
|
||||
this.setState({
|
||||
key: guid(),
|
||||
stack,
|
||||
});
|
||||
// Immediately blow away all current scenes with a new key.
|
||||
this._key = guid();
|
||||
this._applyStack(stack);
|
||||
}
|
||||
|
||||
getCurrentRoutes(): Array<any> {
|
||||
return this.state.stack.toArray();
|
||||
return this._stack.toArray();
|
||||
}
|
||||
|
||||
_jumpToIndex(index: number): void {
|
||||
const {stack} = this.state;
|
||||
const stack = this._stack;
|
||||
if (index < 0 || index >= stack.size) {
|
||||
return;
|
||||
}
|
||||
const nextStack = stack.jumpToIndex(index);
|
||||
this.setState({stack: nextStack});
|
||||
this._applyStack(stack.jumpToIndex(index));
|
||||
}
|
||||
|
||||
// Lyfe cycle and private methods below.
|
||||
|
@ -209,16 +231,22 @@ class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
|||
}
|
||||
|
||||
componentWillMount(): void {
|
||||
this._onNavigationBarRef = this._onNavigationBarRef.bind(this);
|
||||
this._onPositionChange = this._onPositionChange.bind(this);
|
||||
this._renderCard = this._renderCard.bind(this);
|
||||
this._renderHeader = this._renderHeader.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
this._positionListener && this._positionListener.remove();
|
||||
}
|
||||
|
||||
render(): ReactElement {
|
||||
return (
|
||||
<NavigationAnimatedView
|
||||
key={'main_' + this.state.key}
|
||||
navigationState={this.state.stack.toNavigationState()}
|
||||
key={'main_' + this._key}
|
||||
navigationState={this._stack.toNavigationState()}
|
||||
renderOverlay={this._renderHeader}
|
||||
renderScene={this._renderCard}
|
||||
style={this.props.style}
|
||||
|
@ -236,8 +264,26 @@ class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
|||
}
|
||||
|
||||
_renderHeader(props: NavigationSceneRendererProps): ?ReactElement {
|
||||
// TODO(hedger): Render the legacy header.
|
||||
return null;
|
||||
this._positionListener && this._positionListener.remove();
|
||||
this._positionListener = new NavigationAnimatedValueSubscription(
|
||||
props.position,
|
||||
this._onPositionChange,
|
||||
);
|
||||
|
||||
const {navigationBar, navigationBarNavigator} = this.props;
|
||||
|
||||
if (!navigationBar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return React.cloneElement(
|
||||
navigationBar,
|
||||
{
|
||||
ref: this._onNavigationBarRef,
|
||||
navigator: navigationBarNavigator || this,
|
||||
navState: {...this.state},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_renderCard(props: NavigationSceneRendererProps): ReactElement {
|
||||
|
@ -248,7 +294,7 @@ class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
|||
|
||||
if (configureScene) {
|
||||
const route = RouteStack.getRouteByNavigationState(navigationState);
|
||||
const config = configureScene(route, this.state.stack.toArray());
|
||||
const config = configureScene(route, this.state.routeStack);
|
||||
|
||||
switch (getConfigPopDirection(config)) {
|
||||
case 'left-to-right':
|
||||
|
@ -282,6 +328,39 @@ class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
|||
const route = RouteStack.getRouteByNavigationState(navigationState);
|
||||
return this.props.renderScene(route, this);
|
||||
}
|
||||
|
||||
_applyStack(stack: NavigationLegacyNavigatorRouteStack): void {
|
||||
if (stack !== this._stack) {
|
||||
this._previousStack = this._stack;
|
||||
this._stack = stack;
|
||||
this.setState({
|
||||
presentedIndex: stack.index,
|
||||
routeStack: stack.toArray(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_onNavigationBarRef(navigationBarRef: any): void {
|
||||
this._navigationBarRef = navigationBarRef;
|
||||
const {navigationBar} = this.props;
|
||||
if (navigationBar && typeof navigationBar.ref === 'function') {
|
||||
navigationBar.ref(navigationBarRef);
|
||||
}
|
||||
}
|
||||
|
||||
_onPositionChange(data: {value: number}): void {
|
||||
const fromIndex = this._previousStack.index;
|
||||
const toIndex = this._stack.index;
|
||||
|
||||
if (
|
||||
fromIndex !== toIndex &&
|
||||
this._navigationBarRef &&
|
||||
typeof this._navigationBarRef.updateProgress === 'function'
|
||||
) {
|
||||
const progress = (data.value - fromIndex) / (toIndex - fromIndex);
|
||||
this._navigationBarRef.updateProgress(progress, fromIndex, toIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy static members.
|
||||
|
|
|
@ -16,6 +16,7 @@ const NavigationContainer = require('NavigationContainer');
|
|||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
const NavigationStateUtils = require('NavigationStateUtils');
|
||||
const React = require('react-native');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const View = require('View');
|
||||
|
||||
import type {
|
||||
|
@ -211,16 +212,24 @@ class NavigationAnimatedView
|
|||
}
|
||||
|
||||
render(): ReactElement {
|
||||
const overlay = this._renderOverlay();
|
||||
const scenes = this._renderScenes();
|
||||
return (
|
||||
<View
|
||||
onLayout={this._onLayout}
|
||||
style={this.props.style}>
|
||||
{this.state.scenes.map(this._renderScene, this)}
|
||||
{this._renderOverlay()}
|
||||
<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,
|
||||
|
@ -284,6 +293,12 @@ class NavigationAnimatedView
|
|||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
scenes: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
NavigationAnimatedView.propTypes = propTypes;
|
||||
NavigationAnimatedView.defaultProps = defaultProps;
|
||||
|
||||
|
|
Loading…
Reference in New Issue