Skip to content

Commit

Permalink
Add gesture handling for the card stack.
Browse files Browse the repository at this point in the history
Reviewed By: ericvicenti

Differential Revision: D2995958

fb-gh-sync-id: f66759440b03072b650a572f011cadd06a0180d2
shipit-source-id: f66759440b03072b650a572f011cadd06a0180d2
  • Loading branch information
Hedger Wang authored and Facebook Github Bot 2 committed Mar 2, 2016
1 parent 85801ef commit caac520
Show file tree
Hide file tree
Showing 6 changed files with 372 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'use strict';

const NavigationExampleRow = require('./NavigationExampleRow');
const NavigationRootContainer = require('NavigationRootContainer');
const React = require('react-native');

const {
Expand All @@ -25,62 +26,68 @@ const {
const NavigationCardStack = NavigationExperimental.CardStack;
const NavigationStateUtils = NavigationExperimental.StateUtils;

function reduceNavigationState(initialState) {
return (currentState, action) => {
switch (action.type) {
case 'RootContainerInitialAction':
return initialState;

case 'push':
return NavigationStateUtils.push(currentState, {key: action.key});

case 'back':
case 'pop':
return currentState.index > 0 ?
NavigationStateUtils.pop(currentState) :
currentState;

default:
return currentState;
}
};
}

const ExampleReducer = reduceNavigationState({
index: 0,
children: [{key: 'First Route'}],
});

class NavigationCardStackExample extends React.Component {

constructor(props, context) {
super(props, context);
this.state = this._getInitialState();

this._renderNavigation = this._renderNavigation.bind(this);
this._renderScene = this._renderScene.bind(this);
this._push = this._push.bind(this);
this._pop = this._pop.bind(this);
this._toggleDirection = this._toggleDirection.bind(this);

this.state = {isHorizontal: true};
}

render() {
return (
<NavigationCardStack
direction={this.state.isHorizontal ? 'horizontal' : 'vertical'}
navigationState={this.state.navigationState}
renderScene={this._renderScene}
<NavigationRootContainer
reducer={ExampleReducer}
renderNavigation={this._renderNavigation}
style={styles.main}
/>
);
}

_getInitialState() {
const navigationState = {
index: 0,
children: [{key: 'First Route'}],
};
return {
isHorizontal: true,
navigationState,
};
}

_push() {
const state = this.state.navigationState;
const nextState = NavigationStateUtils.push(
state,
{key: 'Route ' + (state.index + 1)},
_renderNavigation(navigationState, onNavigate) {
return (
<NavigationCardStack
direction={this.state.isHorizontal ? 'horizontal' : 'vertical'}
navigationState={navigationState}
onNavigate={onNavigate}
renderScene={this._renderScene}
style={styles.main}
/>
);
this.setState({
navigationState: nextState,
});
}

_pop() {
const state = this.state.navigationState;
const nextState = state.index > 0 ?
NavigationStateUtils.pop(state) :
state;

this.setState({
navigationState: nextState,
});
}

_renderScene(props) {
const {navigationParentState, onNavigate} = props;
return (
<ScrollView style={styles.scrollView}>
<NavigationExampleRow
Expand All @@ -96,11 +103,20 @@ class NavigationCardStackExample extends React.Component {
/>
<NavigationExampleRow
text="Push Route"
onPress={this._push}
onPress={() => {
onNavigate({
type: 'push',
key: 'Route ' + navigationParentState.children.length,
});
}}
/>
<NavigationExampleRow
text="Pop Route"
onPress={this._pop}
onPress={() => {
onNavigate({
type: 'pop',
});
}}
/>
<NavigationExampleRow
text="Exit Card Stack Example"
Expand All @@ -115,6 +131,12 @@ class NavigationCardStackExample extends React.Component {
isHorizontal: !this.state.isHorizontal,
});
}

_onNavigate(action) {
if (action && action.type === 'back') {
this._pop();
}
}
}

const styles = StyleSheet.create({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ const Animated = require('Animated');
const NavigationAnimatedView = require('NavigationAnimatedView');
const NavigationCardStackItem = require('NavigationCardStackItem');
const NavigationContainer = require('NavigationContainer');
const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
const React = require('React');
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
const StyleSheet = require('StyleSheet');

const emptyFunction = require('emptyFunction');

const {PropTypes} = React;
const {Directions} = NavigationCardStackItem;
const {Directions} = NavigationLinearPanResponder;

import type {
NavigationParentState,
} from 'NavigationStateUtils';

import type {
Layout,
NavigationStateRenderer,
NavigationStateRendererProps,
Position,
Expand All @@ -55,7 +55,7 @@ import type {
type Props = {
direction: string,
navigationState: NavigationParentState,
renderOverlay: NavigationStateRenderer,
renderOverlay: ?NavigationStateRenderer,
renderScene: NavigationStateRenderer,
};

Expand Down Expand Up @@ -98,6 +98,7 @@ class NavigationCardStack extends React.Component {
layout,
navigationState,
position,
navigationParentState,
} = props;

return (
Expand All @@ -106,6 +107,7 @@ class NavigationCardStack extends React.Component {
index={index}
key={navigationState.key}
layout={layout}
navigationParentState={navigationParentState}
navigationState={navigationState}
position={position}
renderScene={this.props.renderScene}
Expand Down Expand Up @@ -136,8 +138,6 @@ NavigationCardStack.defaultProps = {
renderOverlay: emptyFunction.thatReturnsNull,
};

NavigationCardStack.Directions = Directions;

const styles = StyleSheet.create({
animatedView: {
flex: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,41 @@

const Animated = require('Animated');
const NavigationContainer = require('NavigationContainer');
const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
const React = require('React');
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
const StyleSheet = require('StyleSheet');
const View = require('View');
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');

const {PropTypes} = React;
const {Directions} = NavigationLinearPanResponder;

import type {
NavigationParentState,
} from 'NavigationStateUtils';


import type {
Layout,
Position,
NavigationStateRenderer,
} from 'NavigationAnimatedView';

import type {
Direction,
OnNavigateHandler,
} from 'NavigationLinearPanResponder';

type AnimatedValue = Animated.Value;

type Props = {
direction: string,
direction: Direction,
index: number;
layout: Layout;
navigationState: NavigationParentState;
position: Position;
renderScene: NavigationStateRenderer;
navigationParentState: NavigationParentState,
navigationState: NavigationParentState,
position: Position,
onNavigate: ?OnNavigateHandler,
renderScene: NavigationStateRenderer,
};

type State = {
Expand All @@ -78,6 +86,39 @@ class AmimatedValueSubscription {
}
}

/**
* Class that provides the required information for the
* `NavigationLinearPanResponder`. This class must implement
* the interface `NavigationLinearPanResponderDelegate`.
*/
class PanResponderDelegate {
_props : Props;

constructor(props: Props) {
this._props = props;
}

getDirection(): Direction {
return this._props.direction;
}

getIndex(): number {
return this._props.navigationParentState.index;
}

getLayout(): Layout {
return this._props.layout;
}

getPosition(): Position {
return this._props.position;
}

onNavigate(action: {type: string}): void {
this._props.onNavigate && this._props.onNavigate(action);
}
}

/**
* Component that renders the scene as card for the <NavigationCardStack />.
*/
Expand Down Expand Up @@ -119,9 +160,8 @@ class NavigationCardStackItem extends React.Component {
const {
direction,
index,
navigationState,
navigationParentState,
position,
layout,
} = this.props;
const {
height,
Expand Down Expand Up @@ -161,8 +201,16 @@ class NavigationCardStackItem extends React.Component {
],
};

let panHandlers = null;
if (navigationParentState.index === index) {
const delegate = new PanResponderDelegate(this.props);
const panResponder = new NavigationLinearPanResponder(delegate);
panHandlers = panResponder.panHandlers;
}

return (
<Animated.View
{...panHandlers}
style={[styles.main, animatedStyle]}>
{this.props.renderScene(this.props)}
</Animated.View>
Expand Down Expand Up @@ -200,16 +248,12 @@ class NavigationCardStackItem extends React.Component {
}
}

const Directions = {
HORIZONTAL: 'horizontal',
VERTICAL: 'vertical',
};

NavigationCardStackItem.propTypes = {
direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
index: PropTypes.number.isRequired,
layout: PropTypes.object.isRequired,
navigationState: PropTypes.object.isRequired,
navigationParentState: PropTypes.object.isRequired,
position: PropTypes.object.isRequired,
renderScene: PropTypes.func.isRequired,
};
Expand All @@ -218,10 +262,6 @@ NavigationCardStackItem.defaultProps = {
direction: Directions.HORIZONTAL,
};

NavigationCardStackItem = NavigationContainer.create(NavigationCardStackItem);

NavigationCardStackItem.Directions = Directions;

const styles = StyleSheet.create({
main: {
backgroundColor: '#E9E9EF',
Expand All @@ -237,6 +277,4 @@ const styles = StyleSheet.create({
},
});



module.exports = NavigationCardStackItem;
module.exports = NavigationContainer.create(NavigationCardStackItem);
Loading

0 comments on commit caac520

Please sign in to comment.