mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-03-29 22:41:56 +08:00
Refactor <NavigationHeader /> API.
Summary:- All the public sub component renderers should implement the interface NavigationSceneRenderer, which will help to reuse renderer or replace renders for different composition. - Perf improvement. <NavigationHeader /> is rendering way more sub component than necessary, we shall fix that. - No UI or behavior change. Reviewed By: ericvicenti Differential Revision: D3091442 fb-gh-sync-id: fba5f7ce74597fa6036b5b216c02b06052801983 shipit-source-id: fba5f7ce74597fa6036b5b216c02b06052801983
This commit is contained in:
committed by
Facebook Github Bot 9
parent
433fb336af
commit
62e80a600e
@@ -58,10 +58,11 @@ const NavigationBasicReducer = NavigationReducer.StackReducer({
|
||||
|
||||
class NavigationAnimatedExample extends React.Component {
|
||||
componentWillMount() {
|
||||
this._renderNavigation = this._renderNavigation.bind(this);
|
||||
this._renderCard = this._renderCard.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._renderHeader = this._renderHeader.bind(this);
|
||||
this._renderNavigation = this._renderNavigation.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._renderTitleComponent = this._renderTitleComponent.bind(this);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
@@ -99,14 +100,20 @@ class NavigationAnimatedExample extends React.Component {
|
||||
_renderHeader(/*NavigationSceneRendererProps*/ props) {
|
||||
return (
|
||||
<NavigationHeader
|
||||
navigationProps={props}
|
||||
renderTitleComponent={(navigationProps, scene) => {
|
||||
return <NavigationHeader.Title>{scene.navigationState.key}</NavigationHeader.Title>;
|
||||
}}
|
||||
{...props}
|
||||
renderTitleComponent={this._renderTitleComponent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_renderTitleComponent(/*NavigationSceneRendererProps*/ props) {
|
||||
return (
|
||||
<NavigationHeader.Title>
|
||||
{props.scene.navigationState.key}
|
||||
</NavigationHeader.Title>
|
||||
);
|
||||
}
|
||||
|
||||
_renderCard(/*NavigationSceneRendererProps*/ props) {
|
||||
return (
|
||||
<NavigationCard
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2013-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.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -139,7 +146,7 @@ const ExampleAppReducer = NavigationReducer.TabsReducer({
|
||||
],
|
||||
});
|
||||
|
||||
function stateTypeTitleMap(pageState) {
|
||||
function stateTypeTitleMap(pageState: any) {
|
||||
switch (pageState.type) {
|
||||
case 'ProfilePage':
|
||||
return 'Profile Page';
|
||||
@@ -177,14 +184,20 @@ class ExampleTabScreen extends React.Component {
|
||||
_renderHeader(props: NavigationSceneRendererProps) {
|
||||
return (
|
||||
<NavigationHeader
|
||||
navigationProps={props}
|
||||
renderTitleComponent={(navigationProps, scene) => {
|
||||
return <NavigationHeader.Title>{stateTypeTitleMap(scene.navigationState)}</NavigationHeader.Title>;
|
||||
}}
|
||||
{...props}
|
||||
renderTitleComponent={this._renderTitleComponent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_renderTitleComponent(props: NavigationSceneRendererProps) {
|
||||
return (
|
||||
<NavigationHeader.Title>
|
||||
{stateTypeTitleMap(props.scene.navigationState)}
|
||||
</NavigationHeader.Title>
|
||||
);
|
||||
}
|
||||
|
||||
_renderScene(props: NavigationSceneRendererProps) {
|
||||
const {onNavigate} = props;
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2013-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.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -77,10 +84,12 @@ class UIExplorerApp extends React.Component {
|
||||
_renderOverlay: Function;
|
||||
_renderScene: Function;
|
||||
_renderCard: Function;
|
||||
_renderTitleComponent: Function;
|
||||
componentWillMount() {
|
||||
this._renderNavigation = this._renderNavigation.bind(this);
|
||||
this._renderOverlay = this._renderOverlay.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._renderTitleComponent = this._renderTitleComponent.bind(this);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
@@ -121,15 +130,20 @@ class UIExplorerApp extends React.Component {
|
||||
_renderOverlay(props: NavigationSceneRendererProps): ReactElement {
|
||||
return (
|
||||
<NavigationHeader
|
||||
key={'header_' + props.scene.navigationState.key}
|
||||
navigationProps={props}
|
||||
renderTitleComponent={(navigationProps, scene) => {
|
||||
return <NavigationHeader.Title>{UIExplorerStateTitleMap(scene.navigationState)}</NavigationHeader.Title>;
|
||||
}}
|
||||
{...props}
|
||||
renderTitleComponent={this._renderTitleComponent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_renderTitleComponent(props: NavigationSceneRendererProps): ReactElement {
|
||||
return (
|
||||
<NavigationHeader.Title>
|
||||
{UIExplorerStateTitleMap(props.scene.navigationState)}
|
||||
</NavigationHeader.Title>
|
||||
);
|
||||
}
|
||||
|
||||
_renderScene(props: NavigationSceneRendererProps): ?ReactElement {
|
||||
const state = props.scene.navigationState;
|
||||
if (state.key === 'AppList') {
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||
* Copyright (c) 2013-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.
|
||||
*
|
||||
* Facebook, Inc. ("Facebook") owns all right, title and interest, including
|
||||
* all intellectual property and other proprietary rights, in and to the React
|
||||
@@ -32,6 +37,8 @@ const NavigationContainer = require('NavigationContainer');
|
||||
const NavigationHeaderTitle = require('NavigationHeaderTitle');
|
||||
const NavigationHeaderBackButton = require('NavigationHeaderBackButton');
|
||||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
const NavigationHeaderStyleInterpolator = require('NavigationHeaderStyleInterpolator');
|
||||
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||
|
||||
const {
|
||||
Animated,
|
||||
@@ -41,210 +48,197 @@ const {
|
||||
} = React;
|
||||
|
||||
import type {
|
||||
NavigationSceneRenderer,
|
||||
NavigationSceneRendererProps,
|
||||
NavigationScene,
|
||||
NavigationStyleInterpolator,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
type Renderer = (props: NavigationSceneRendererProps, scene: NavigationScene) => ?ReactElement;
|
||||
|
||||
type DefaultProps = {
|
||||
renderTitleComponent: Renderer;
|
||||
renderLeftComponent: Renderer;
|
||||
renderLeftComponent: NavigationSceneRenderer,
|
||||
renderRightComponent: NavigationSceneRenderer,
|
||||
renderTitleComponent: NavigationSceneRenderer,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
navigationProps: NavigationSceneRendererProps;
|
||||
renderTitleComponent: Renderer;
|
||||
renderLeftComponent: Renderer;
|
||||
renderRightComponent: Renderer;
|
||||
type Props = NavigationSceneRendererProps & {
|
||||
renderLeftComponent: NavigationSceneRenderer,
|
||||
renderRightComponent: NavigationSceneRenderer,
|
||||
renderTitleComponent: NavigationSceneRenderer,
|
||||
style?: any;
|
||||
}
|
||||
};
|
||||
|
||||
type SubViewName = 'left' | 'title' | 'right';
|
||||
|
||||
const APPBAR_HEIGHT = Platform.OS === 'ios' ? 44 : 56;
|
||||
const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 : 0;
|
||||
const {PropTypes} = React;
|
||||
|
||||
class NavigationHeader extends React.Component<DefaultProps, Props, any> {
|
||||
props: Props;
|
||||
|
||||
class NavigationHeader extends React.Component<DefaultProps, Props, void> {
|
||||
static defaultProps = {
|
||||
renderTitleComponent: (props, scene) => {
|
||||
const pageState = scene.navigationState;
|
||||
|
||||
return <NavigationHeaderTitle>{pageState.title ? pageState.title : ''}</NavigationHeaderTitle>;
|
||||
renderTitleComponent: (props: NavigationSceneRendererProps) => {
|
||||
const {navigationState} = props;
|
||||
const title = String(navigationState.title || '');
|
||||
return <NavigationHeaderTitle>{title}</NavigationHeaderTitle>;
|
||||
},
|
||||
|
||||
renderLeftComponent: (props: NavigationSceneRendererProps) => {
|
||||
return props.scene.index > 0 ? <NavigationHeaderBackButton /> : null;
|
||||
},
|
||||
|
||||
renderRightComponent: (props: NavigationSceneRendererProps) => {
|
||||
return null;
|
||||
},
|
||||
renderLeftComponent: (props, scene) => scene.index !== 0 ? <NavigationHeaderBackButton /> : null
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
navigationProps: React.PropTypes.shape(NavigationPropTypes.SceneRenderer).isRequired,
|
||||
renderTitleComponent: React.PropTypes.func,
|
||||
renderLeftComponent: React.PropTypes.func,
|
||||
renderRightComponent: React.PropTypes.func,
|
||||
...NavigationPropTypes.SceneRenderer,
|
||||
renderLeftComponent: PropTypes.func,
|
||||
renderRightComponent: PropTypes.func,
|
||||
renderTitleComponent: PropTypes.func,
|
||||
style: View.propTypes.style,
|
||||
};
|
||||
|
||||
_renderLeftComponent(scene: NavigationScene) {
|
||||
const {
|
||||
renderLeftComponent,
|
||||
navigationProps,
|
||||
} = this.props;
|
||||
|
||||
if (renderLeftComponent) {
|
||||
const {
|
||||
index,
|
||||
navigationState,
|
||||
} = scene;
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
pointerEvents={navigationProps.navigationState.index === index ? 'auto' : 'none'}
|
||||
key={navigationState.key}
|
||||
style={[
|
||||
styles.left,
|
||||
{
|
||||
opacity: navigationProps.position.interpolate({
|
||||
inputRange: [ index - 1, index, index + 1 ],
|
||||
outputRange: [ 0, 1, 0 ],
|
||||
})
|
||||
}
|
||||
]}
|
||||
>
|
||||
{renderLeftComponent(navigationProps, scene)}
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
shouldComponentUpdate(nextProps: Props, nextState: any): boolean {
|
||||
return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call(
|
||||
this,
|
||||
nextProps,
|
||||
nextState
|
||||
);
|
||||
}
|
||||
|
||||
_renderRightComponent(scene: NavigationScene) {
|
||||
const {
|
||||
renderRightComponent,
|
||||
navigationProps,
|
||||
} = this.props;
|
||||
render(): ReactElement {
|
||||
const { scenes, style } = this.props;
|
||||
|
||||
if (renderRightComponent) {
|
||||
const {
|
||||
index,
|
||||
navigationState,
|
||||
} = scene;
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
pointerEvents={navigationProps.navigationState.index === index ? 'auto' : 'none'}
|
||||
key={navigationState.key}
|
||||
style={[
|
||||
styles.right,
|
||||
{
|
||||
opacity: navigationProps.position.interpolate({
|
||||
inputRange: [ index - 1, index, index + 1 ],
|
||||
outputRange: [ 0, 1, 0 ],
|
||||
})
|
||||
}
|
||||
]}
|
||||
>
|
||||
{renderRightComponent(navigationProps, scene)}
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_renderTitleComponent(scene: NavigationScene) {
|
||||
const {
|
||||
renderTitleComponent,
|
||||
navigationProps,
|
||||
} = this.props;
|
||||
|
||||
if (renderTitleComponent) {
|
||||
const {
|
||||
index,
|
||||
navigationState,
|
||||
} = scene;
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
pointerEvents={navigationProps.navigationState.index === index ? 'auto' : 'none'}
|
||||
key={navigationState.key}
|
||||
style={[
|
||||
styles.title,
|
||||
{
|
||||
opacity: navigationProps.position.interpolate({
|
||||
inputRange: [ index - 1, index, index + 1 ],
|
||||
outputRange: [ 0, 1, 0 ],
|
||||
}),
|
||||
transform: [
|
||||
{
|
||||
translateX: navigationProps.position.interpolate({
|
||||
inputRange: [ index - 1, index + 1 ],
|
||||
outputRange: [ 200, -200 ],
|
||||
}),
|
||||
}
|
||||
],
|
||||
}
|
||||
]}
|
||||
>
|
||||
{renderTitleComponent(navigationProps, scene)}
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { scenes } = this.props.navigationProps;
|
||||
const scenesProps = scenes.map(scene => {
|
||||
const props = NavigationPropTypes.extractSceneRendererProps(this.props);
|
||||
props.scene = scene;
|
||||
return props;
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={[ styles.appbar, this.props.style ]}>
|
||||
{scenes.map(this._renderLeftComponent, this)}
|
||||
{scenes.map(this._renderTitleComponent, this)}
|
||||
{scenes.map(this._renderRightComponent, this)}
|
||||
<View style={[ styles.appbar, style ]}>
|
||||
{scenesProps.map(this._renderLeft, this)}
|
||||
{scenesProps.map(this._renderTitle, this)}
|
||||
{scenesProps.map(this._renderRight, this)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderLeft(props: NavigationSceneRendererProps): ?ReactElement {
|
||||
return this._renderSubView(
|
||||
props,
|
||||
'left',
|
||||
this.props.renderLeftComponent,
|
||||
NavigationHeaderStyleInterpolator.forLeft,
|
||||
);
|
||||
}
|
||||
|
||||
_renderTitle(props: NavigationSceneRendererProps): ?ReactElement {
|
||||
return this._renderSubView(
|
||||
props,
|
||||
'title',
|
||||
this.props.renderTitleComponent,
|
||||
NavigationHeaderStyleInterpolator.forCenter,
|
||||
);
|
||||
}
|
||||
|
||||
_renderRight(props: NavigationSceneRendererProps): ?ReactElement {
|
||||
return this._renderSubView(
|
||||
props,
|
||||
'right',
|
||||
this.props.renderRightComponent,
|
||||
NavigationHeaderStyleInterpolator.forRight,
|
||||
);
|
||||
}
|
||||
|
||||
_renderSubView(
|
||||
props: NavigationSceneRendererProps,
|
||||
name: SubViewName,
|
||||
renderer: NavigationSceneRenderer,
|
||||
styleInterpolator: NavigationStyleInterpolator,
|
||||
): ?ReactElement {
|
||||
const {
|
||||
scene,
|
||||
navigationState,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
index,
|
||||
isStale,
|
||||
key,
|
||||
} = scene;
|
||||
|
||||
const offset = navigationState.index - index;
|
||||
|
||||
if (Math.abs(offset) > 2) {
|
||||
// Scene is far away from the active scene. Hides it to avoid unnecessary
|
||||
// rendering.
|
||||
return null;
|
||||
}
|
||||
|
||||
const subView = renderer(props);
|
||||
if (subView === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pointerEvents = offset !== 0 || isStale ? 'none' : 'auto';
|
||||
return (
|
||||
<Animated.View
|
||||
pointerEvents={pointerEvents}
|
||||
key={name + '_' + key}
|
||||
style={[
|
||||
styles[name],
|
||||
styleInterpolator(props),
|
||||
]}>
|
||||
{subView}
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
appbar: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
backgroundColor: Platform.OS === 'ios' ? '#EFEFF2' : '#FFF',
|
||||
borderBottomWidth: Platform.OS === 'ios' ? StyleSheet.hairlineWidth : 0,
|
||||
borderBottomColor: 'rgba(0, 0, 0, .15)',
|
||||
height: APPBAR_HEIGHT + STATUSBAR_HEIGHT,
|
||||
marginBottom: 16, // This is needed for elevation shadow
|
||||
borderBottomWidth: Platform.OS === 'ios' ? StyleSheet.hairlineWidth : 0,
|
||||
elevation: 2,
|
||||
flexDirection: 'row',
|
||||
height: APPBAR_HEIGHT + STATUSBAR_HEIGHT,
|
||||
justifyContent: 'flex-start',
|
||||
left: 0,
|
||||
marginBottom: 16, // This is needed for elevation shadow
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
},
|
||||
|
||||
title: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: APPBAR_HEIGHT,
|
||||
right: APPBAR_HEIGHT,
|
||||
marginTop: STATUSBAR_HEIGHT,
|
||||
position: 'absolute',
|
||||
right: APPBAR_HEIGHT,
|
||||
top: 0,
|
||||
},
|
||||
|
||||
left: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
marginTop: STATUSBAR_HEIGHT,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
},
|
||||
|
||||
right: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
marginTop: STATUSBAR_HEIGHT,
|
||||
}
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
},
|
||||
});
|
||||
|
||||
NavigationHeader = NavigationContainer.create(NavigationHeader);
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2013-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.
|
||||
*
|
||||
* 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 NavigationHeaderStyleInterpolator
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
||||
import type {
|
||||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
/**
|
||||
* Utility that builds the style for the navigation header.
|
||||
*
|
||||
* +-------------+-------------+-------------+
|
||||
* | | | |
|
||||
* | Left | Title | Right |
|
||||
* | Component | Component | Component |
|
||||
* | | | |
|
||||
* +-------------+-------------+-------------+
|
||||
*/
|
||||
|
||||
function forLeft(props: NavigationSceneRendererProps): Object {
|
||||
const {position, scene} = props;
|
||||
const {index} = scene;
|
||||
return {
|
||||
opacity: position.interpolate({
|
||||
inputRange: [ index - 1, index, index + 1 ],
|
||||
outputRange: [ 0, 1, 0 ],
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
function forCenter(props: NavigationSceneRendererProps): Object {
|
||||
const {position, scene} = props;
|
||||
const {index} = scene;
|
||||
return {
|
||||
opacity:position.interpolate({
|
||||
inputRange: [ index - 1, index, index + 1 ],
|
||||
outputRange: [ 0, 1, 0 ],
|
||||
}),
|
||||
transform: [
|
||||
{
|
||||
translateX: position.interpolate({
|
||||
inputRange: [ index - 1, index + 1 ],
|
||||
outputRange: [ 200, -200 ],
|
||||
}),
|
||||
}
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function forRight(props: NavigationSceneRendererProps): Object {
|
||||
const {position, scene} = props;
|
||||
const {index} = scene;
|
||||
return {
|
||||
opacity: position.interpolate({
|
||||
inputRange: [ index - 1, index, index + 1 ],
|
||||
outputRange: [ 0, 1, 0 ],
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
forCenter,
|
||||
forLeft,
|
||||
forRight,
|
||||
};
|
||||
@@ -11,6 +11,10 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
import type {
|
||||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
/**
|
||||
* React component PropTypes Definitions. Consider using this as a supplementary
|
||||
* measure with `NavigationTypeDefinition`. This helps to capture the propType
|
||||
@@ -55,6 +59,7 @@ const layout = PropTypes.shape({
|
||||
const scene = PropTypes.shape({
|
||||
index: PropTypes.number.isRequired,
|
||||
isStale: PropTypes.bool.isRequired,
|
||||
key: PropTypes.string.isRequired,
|
||||
navigationState,
|
||||
});
|
||||
|
||||
@@ -84,8 +89,30 @@ const panHandlers = PropTypes.shape({
|
||||
onStartShouldSetResponderCapture: PropTypes.func.isRequired,
|
||||
});
|
||||
|
||||
/**
|
||||
* Helper function that extracts the props needed for scene renderer.
|
||||
*/
|
||||
function extractSceneRendererProps(
|
||||
props: NavigationSceneRendererProps,
|
||||
): NavigationSceneRendererProps {
|
||||
return {
|
||||
layout: props.layout,
|
||||
navigationState: props.navigationState,
|
||||
onNavigate: props.onNavigate,
|
||||
position: props.position,
|
||||
scene: props.scene,
|
||||
scenes: props.scenes,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
// helpers
|
||||
extractSceneRendererProps,
|
||||
|
||||
// Bundled propTypes.
|
||||
SceneRenderer,
|
||||
|
||||
// propTypes
|
||||
action,
|
||||
navigationParentState,
|
||||
navigationState,
|
||||
|
||||
@@ -107,3 +107,8 @@ export type NavigationReducer = (
|
||||
export type NavigationSceneRenderer = (
|
||||
props: NavigationSceneRendererProps,
|
||||
) => ?ReactElement;
|
||||
|
||||
export type NavigationStyleInterpolator = (
|
||||
props: NavigationSceneRendererProps,
|
||||
) => Object;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user