mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-24 12:35:39 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67233dc9ef | ||
|
|
b0443c1861 | ||
|
|
c0b637df52 | ||
|
|
9a82706fba | ||
|
|
d973a26edb | ||
|
|
852e7e1974 | ||
|
|
cd3707d64b | ||
|
|
3c36db455f | ||
|
|
ec52c884c5 | ||
|
|
c4b3f25a0f | ||
|
|
93642e16e7 | ||
|
|
1a76556290 | ||
|
|
12b21f052e |
26
CHANGELOG.md
26
CHANGELOG.md
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2.9.1] - [2018-07-24](https://github.com/react-navigation/react-navigation/releases/tag/2.9.1)
|
||||
### Fixed
|
||||
- Incorrect parameters passed to title offset calculation led to bug in header layout when no right component (https://github.com/react-navigation/react-navigation/issues/4754)
|
||||
|
||||
## [2.9.0] - [2018-07-20](https://github.com/react-navigation/react-navigation/releases/tag/2.9.0)
|
||||
### Added
|
||||
- `headerLayoutPreset: 'center' | 'left'` to provide an easy solution for [questions like this](https://github.com/react-navigation/react-navigation/issues/4615).
|
||||
- `headerBackTitleEnabled` - this configuration option for stack navigator allows you to force back button titles to either be rendered or not (if you disagree with defaults for your platform and layout preset).
|
||||
|
||||
### Fixed
|
||||
- Android back button ripple is now appropriately sized (fixes [#3955](https://github.com/react-navigation/react-navigation/issues/3955)).
|
||||
- Respect header background color on container (fixes edge case where user depended on displaying content that was rendered behind the navigator, this particular behavior should not be depended on and may break in the future, but this change is still useful regardless).
|
||||
|
||||
|
||||
## [2.8.0] - [2018-07-19](https://github.com/react-navigation/react-navigation/releases/tag/2.8.0)
|
||||
### Added
|
||||
- `headerLeftContainerStyle`, `headerTitleContainerStyle`, and `headerRightContainerStyle` are exposed on `navigationOptions`. These properties allow you to customize the style of the container of `headerLeft`, `headerTitle` and `headerRight` components.
|
||||
|
||||
### Fixed
|
||||
- Fixed memory leaks in `createNavigator`: [closure scope leak](https://github.com/react-navigation/react-navigation/commit/1a765562905e93bbae0262dd20c2688221c999e8), and [clean up old descriptors](https://github.com/react-navigation/react-navigation/commit/93642e16e7ff029586b68ee732ec790504ee4862).
|
||||
|
||||
## [2.7.0] - [2018-07-17](https://github.com/react-navigation/react-navigation/releases/tag/2.7.0)
|
||||
### Added
|
||||
- The enableURLHandling prop on the top level navigator component allows you to disable deep linking handling. Currently it is always enabled. To disable it, `<RootNavigator enableURLHandling={false} />`
|
||||
@@ -83,7 +104,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
### Changed
|
||||
- Improved examples
|
||||
|
||||
[Unreleased]: https://github.com/react-navigation/react-navigation/compare/2.7.0...HEAD
|
||||
[Unreleased]: https://github.com/react-navigation/react-navigation/compare/2.9.1...HEAD
|
||||
[2.9.1]: https://github.com/react-navigation/react-navigation/compare/2.9.0...2.9.1
|
||||
[2.9.0]: https://github.com/react-navigation/react-navigation/compare/2.8.0...2.9.0
|
||||
[2.8.0]: https://github.com/react-navigation/react-navigation/compare/2.7.0...2.8.0
|
||||
[2.7.0]: https://github.com/react-navigation/react-navigation/compare/2.6.2...2.7.0
|
||||
[2.6.2]: https://github.com/react-navigation/react-navigation/compare/2.6.1...2.6.2
|
||||
[2.6.1]: https://github.com/react-navigation/react-navigation/compare/2.6.0...2.6.1
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
"splash": {
|
||||
"image": "./assets/icons/splash.png"
|
||||
},
|
||||
"sdkVersion": "27.0.0",
|
||||
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
"sdkVersion": "28.0.0",
|
||||
"assetBundlePatterns": [
|
||||
"**/*"
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
} from 'react-navigation';
|
||||
|
||||
import * as React from 'react';
|
||||
import { ScrollView, StatusBar } from 'react-native';
|
||||
import { Platform, ScrollView, StatusBar } from 'react-native';
|
||||
import {
|
||||
createStackNavigator,
|
||||
SafeAreaView,
|
||||
@@ -24,6 +24,8 @@ import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
import { HeaderButtons } from './commonComponents/HeaderButtons';
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
type MyNavScreenProps = {
|
||||
navigation: NavigationScreenProp<NavigationState>,
|
||||
banner: React.Node,
|
||||
@@ -133,16 +135,16 @@ class MyHomeScreen extends React.Component<MyHomeScreenProps> {
|
||||
this._s3.remove();
|
||||
}
|
||||
_onWF = a => {
|
||||
console.log('_willFocus HomeScreen', a);
|
||||
DEBUG && console.log('_willFocus HomeScreen', a);
|
||||
};
|
||||
_onDF = a => {
|
||||
console.log('_didFocus HomeScreen', a);
|
||||
DEBUG && console.log('_didFocus HomeScreen', a);
|
||||
};
|
||||
_onWB = a => {
|
||||
console.log('_willBlur HomeScreen', a);
|
||||
DEBUG && console.log('_willBlur HomeScreen', a);
|
||||
};
|
||||
_onDB = a => {
|
||||
console.log('_didBlur HomeScreen', a);
|
||||
DEBUG && console.log('_didBlur HomeScreen', a);
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -177,16 +179,16 @@ class MyPhotosScreen extends React.Component<MyPhotosScreenProps> {
|
||||
this._s3.remove();
|
||||
}
|
||||
_onWF = a => {
|
||||
console.log('_willFocus PhotosScreen', a);
|
||||
DEBUG && console.log('_willFocus PhotosScreen', a);
|
||||
};
|
||||
_onDF = a => {
|
||||
console.log('_didFocus PhotosScreen', a);
|
||||
DEBUG && console.log('_didFocus PhotosScreen', a);
|
||||
};
|
||||
_onWB = a => {
|
||||
console.log('_willBlur PhotosScreen', a);
|
||||
DEBUG && console.log('_willBlur PhotosScreen', a);
|
||||
};
|
||||
_onDB = a => {
|
||||
console.log('_didBlur PhotosScreen', a);
|
||||
DEBUG && console.log('_didBlur PhotosScreen', a);
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -231,18 +233,23 @@ MyProfileScreen.navigationOptions = props => {
|
||||
};
|
||||
};
|
||||
|
||||
const SimpleStack = createStackNavigator({
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
const SimpleStack = createStackNavigator(
|
||||
{
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
},
|
||||
Profile: {
|
||||
path: 'people/:name',
|
||||
screen: MyProfileScreen,
|
||||
},
|
||||
Photos: {
|
||||
path: 'photos/:name',
|
||||
screen: MyPhotosScreen,
|
||||
},
|
||||
},
|
||||
Profile: {
|
||||
path: 'people/:name',
|
||||
screen: MyProfileScreen,
|
||||
},
|
||||
Photos: {
|
||||
path: 'photos/:name',
|
||||
screen: MyPhotosScreen,
|
||||
},
|
||||
});
|
||||
{
|
||||
// headerLayoutPreset: 'center',
|
||||
}
|
||||
);
|
||||
|
||||
export default SimpleStack;
|
||||
|
||||
@@ -2,23 +2,23 @@
|
||||
"name": "NavigationPlayground",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
"main": "node_modules/expo/AppEntry.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "react-native-scripts start",
|
||||
"eject": "react-native-scripts eject",
|
||||
"android": "react-native-scripts android",
|
||||
"ios": "react-native-scripts ios",
|
||||
"start": "expo start",
|
||||
"android": "expo start --android",
|
||||
"ios": "expo start --ios",
|
||||
"test": "flow"
|
||||
},
|
||||
"dependencies": {
|
||||
"expo": "^27.0.0",
|
||||
"expo": "^28.0.0",
|
||||
"invariant": "^2.2.4",
|
||||
"react": "16.3.1",
|
||||
"react-native": "^0.55.0",
|
||||
"react-native-iphone-x-helper": "^1.0.2",
|
||||
"react-navigation": "link:../..",
|
||||
"react-navigation-header-buttons": "^0.0.4",
|
||||
"react-navigation-material-bottom-tabs": "0.1.3",
|
||||
"react-navigation-material-bottom-tabs": "^0.3.0",
|
||||
"react-navigation-tabs": "^0.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -26,9 +26,8 @@
|
||||
"babel-plugin-transform-remove-console": "^6.9.0",
|
||||
"flow-bin": "^0.67.0",
|
||||
"jest": "^22.1.3",
|
||||
"jest-expo": "^26.0.0",
|
||||
"react-native-scripts": "^1.5.0",
|
||||
"react-test-renderer": "16.3.0-alpha.1"
|
||||
"jest-expo": "^28.0.0",
|
||||
"react-test-renderer": "16.3.1"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-expo",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-navigation",
|
||||
"version": "2.7.0",
|
||||
"version": "2.9.1",
|
||||
"description": "Routing and navigation for your React Native apps",
|
||||
"main": "src/react-navigation.js",
|
||||
"repository": {
|
||||
|
||||
@@ -81,7 +81,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#F7F7F7",
|
||||
"backgroundColor": "red",
|
||||
"transform": Array [
|
||||
Object {
|
||||
"translateX": 0,
|
||||
@@ -285,7 +285,7 @@ exports[`StackNavigator renders successfully 1`] = `
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#F7F7F7",
|
||||
"backgroundColor": "red",
|
||||
"transform": Array [
|
||||
Object {
|
||||
"translateX": 0,
|
||||
|
||||
@@ -24,7 +24,7 @@ function createNavigator(NavigatorView, router, navigationConfig) {
|
||||
);
|
||||
}
|
||||
|
||||
const descriptors = { ...prevState.descriptors };
|
||||
const descriptors = {};
|
||||
|
||||
routes.forEach(route => {
|
||||
if (
|
||||
@@ -36,8 +36,10 @@ function createNavigator(NavigatorView, router, navigationConfig) {
|
||||
descriptors[route.key] = prevDescriptors[route.key];
|
||||
return;
|
||||
}
|
||||
const getComponent = () =>
|
||||
router.getComponentForRouteName(route.routeName);
|
||||
const getComponent = router.getComponentForRouteName.bind(
|
||||
null,
|
||||
route.routeName
|
||||
);
|
||||
const childNavigation = navigation.getChildNavigation(route.key);
|
||||
const options = router.getScreenOptions(childNavigation, screenProps);
|
||||
descriptors[route.key] = {
|
||||
|
||||
@@ -21,7 +21,47 @@ import withOrientation from '../withOrientation';
|
||||
|
||||
const APPBAR_HEIGHT = Platform.OS === 'ios' ? 44 : 56;
|
||||
const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 : 0;
|
||||
const TITLE_OFFSET = Platform.OS === 'ios' ? 70 : 56;
|
||||
|
||||
// These can be adjusted by using headerTitleContainerStyle on navigationOptions
|
||||
const TITLE_OFFSET_CENTER_ALIGN = Platform.OS === 'ios' ? 70 : 56;
|
||||
const TITLE_OFFSET_LEFT_ALIGN = Platform.OS === 'ios' ? 20 : 56;
|
||||
|
||||
const getTitleOffsets = (
|
||||
layoutPreset,
|
||||
forceBackTitle,
|
||||
hasLeftComponent,
|
||||
hasRightComponent
|
||||
) => {
|
||||
if (layoutPreset === 'left') {
|
||||
// Maybe at some point we should do something different if the back title is
|
||||
// explicitly enabled, for now people can control it manually
|
||||
|
||||
let style = {
|
||||
left: TITLE_OFFSET_LEFT_ALIGN,
|
||||
right: TITLE_OFFSET_LEFT_ALIGN,
|
||||
};
|
||||
|
||||
if (!hasLeftComponent) {
|
||||
style.left = 0;
|
||||
}
|
||||
if (!hasRightComponent) {
|
||||
style.right = 0;
|
||||
}
|
||||
|
||||
return style;
|
||||
} else if (layoutPreset === 'center') {
|
||||
let style = {
|
||||
left: TITLE_OFFSET_CENTER_ALIGN,
|
||||
right: TITLE_OFFSET_CENTER_ALIGN,
|
||||
};
|
||||
if (!hasLeftComponent && !hasRightComponent) {
|
||||
style.left = 0;
|
||||
style.right = 0;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
};
|
||||
|
||||
const getAppBarHeight = isLandscape => {
|
||||
return Platform.OS === 'ios'
|
||||
@@ -92,6 +132,7 @@ class Header extends React.PureComponent {
|
||||
}
|
||||
|
||||
_renderTitleComponent = props => {
|
||||
const { layoutPreset } = this.props;
|
||||
const { options } = props.scene.descriptor;
|
||||
const headerTitle = options.headerTitle;
|
||||
if (React.isValidElement(headerTitle)) {
|
||||
@@ -103,10 +144,10 @@ class Header extends React.PureComponent {
|
||||
const color = options.headerTintColor;
|
||||
const allowFontScaling = options.headerTitleAllowFontScaling;
|
||||
|
||||
// On iOS, width of left/right components depends on the calculated
|
||||
// size of the title.
|
||||
const onLayoutIOS =
|
||||
Platform.OS === 'ios'
|
||||
// When title is centered, the width of left/right components depends on the
|
||||
// calculated size of the title.
|
||||
const onLayout =
|
||||
layoutPreset === 'center'
|
||||
? e => {
|
||||
this.setState({
|
||||
widths: {
|
||||
@@ -117,18 +158,24 @@ class Header extends React.PureComponent {
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const RenderedHeaderTitle =
|
||||
const HeaderTitleComponent =
|
||||
headerTitle && typeof headerTitle !== 'string'
|
||||
? headerTitle
|
||||
: HeaderTitle;
|
||||
return (
|
||||
<RenderedHeaderTitle
|
||||
onLayout={onLayoutIOS}
|
||||
<HeaderTitleComponent
|
||||
onLayout={onLayout}
|
||||
allowFontScaling={allowFontScaling == null ? true : allowFontScaling}
|
||||
style={[color ? { color } : null, titleStyle]}
|
||||
style={[
|
||||
color ? { color } : null,
|
||||
layoutPreset === 'center'
|
||||
? { textAlign: 'center' }
|
||||
: { textAlign: 'left' },
|
||||
titleStyle,
|
||||
]}
|
||||
>
|
||||
{titleString}
|
||||
</RenderedHeaderTitle>
|
||||
</HeaderTitleComponent>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -167,7 +214,9 @@ class Header extends React.PureComponent {
|
||||
backImage={options.headerBackImage}
|
||||
title={backButtonTitle}
|
||||
truncatedTitle={truncatedBackButtonTitle}
|
||||
backTitleVisible={this.props.backTitleVisible}
|
||||
titleStyle={options.headerBackTitleStyle}
|
||||
layoutPreset={this.props.layoutPreset}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
@@ -220,6 +269,11 @@ class Header extends React.PureComponent {
|
||||
|
||||
const { transitionPreset } = this.props;
|
||||
|
||||
let { style } = props;
|
||||
if (options.headerLeftContainerStyle) {
|
||||
style = [style, options.headerLeftContainerStyle];
|
||||
}
|
||||
|
||||
// On Android, or if we have a custom header left, or if we have a custom back image, we
|
||||
// do not use the modular header (which is the one that imitates UINavigationController)
|
||||
if (
|
||||
@@ -229,14 +283,14 @@ class Header extends React.PureComponent {
|
||||
options.headerLeft === null
|
||||
) {
|
||||
return this._renderSubView(
|
||||
props,
|
||||
{ ...props, style },
|
||||
'left',
|
||||
this._renderLeftComponent,
|
||||
this.props.leftInterpolator
|
||||
);
|
||||
} else {
|
||||
return this._renderModularSubView(
|
||||
props,
|
||||
{ ...props, style },
|
||||
'left',
|
||||
this._renderModularLeftComponent,
|
||||
this.props.leftLabelInterpolator,
|
||||
@@ -246,24 +300,17 @@ class Header extends React.PureComponent {
|
||||
}
|
||||
|
||||
_renderTitle(props, options) {
|
||||
const style = {};
|
||||
const { transitionPreset } = this.props;
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
if (!options.hasLeftComponent) {
|
||||
style.left = 0;
|
||||
}
|
||||
if (!options.hasRightComponent) {
|
||||
style.right = 0;
|
||||
}
|
||||
} else if (
|
||||
Platform.OS === 'ios' &&
|
||||
!options.hasLeftComponent &&
|
||||
!options.hasRightComponent
|
||||
) {
|
||||
style.left = 0;
|
||||
style.right = 0;
|
||||
}
|
||||
const { layoutPreset, transitionPreset } = this.props;
|
||||
let style = [
|
||||
{ justifyContent: layoutPreset === 'center' ? 'center' : 'flex-start' },
|
||||
getTitleOffsets(
|
||||
layoutPreset,
|
||||
false,
|
||||
options.hasLeftComponent,
|
||||
options.hasRightComponent
|
||||
),
|
||||
options.headerTitleContainerStyle,
|
||||
];
|
||||
|
||||
return this._renderSubView(
|
||||
{ ...props, style },
|
||||
@@ -276,8 +323,15 @@ class Header extends React.PureComponent {
|
||||
}
|
||||
|
||||
_renderRight(props) {
|
||||
const { options } = props.scene.descriptor;
|
||||
|
||||
let { style } = props;
|
||||
if (options.headerRightContainerStyle) {
|
||||
style = [style, options.headerRightContainerStyle];
|
||||
}
|
||||
|
||||
return this._renderSubView(
|
||||
props,
|
||||
{ ...props, style },
|
||||
'right',
|
||||
this._renderRightComponent,
|
||||
this.props.rightInterpolator
|
||||
@@ -371,7 +425,6 @@ class Header extends React.PureComponent {
|
||||
styles[name],
|
||||
props.style,
|
||||
styleInterpolator({
|
||||
// todo: determine if we really need to splat all this.props
|
||||
...this.props,
|
||||
...props,
|
||||
}),
|
||||
@@ -392,6 +445,7 @@ class Header extends React.PureComponent {
|
||||
const title = this._renderTitle(props, {
|
||||
hasLeftComponent: !!left,
|
||||
hasRightComponent: !!right,
|
||||
headerTitleContainerStyle: options.headerTitleContainerStyle,
|
||||
});
|
||||
|
||||
const { isLandscape, transitionPreset } = this.props;
|
||||
@@ -527,8 +581,11 @@ class Header extends React.PureComponent {
|
||||
<Animated.View
|
||||
style={[
|
||||
this.props.layoutInterpolator(this.props),
|
||||
Platform.OS === 'ios'
|
||||
? { backgroundColor: DEFAULT_BACKGROUND_COLOR }
|
||||
Platform.OS === 'ios' && !options.headerTransparent
|
||||
? {
|
||||
backgroundColor:
|
||||
safeHeaderStyle.backgroundColor || DEFAULT_BACKGROUND_COLOR,
|
||||
}
|
||||
: null,
|
||||
]}
|
||||
>
|
||||
@@ -620,12 +677,9 @@ const styles = StyleSheet.create({
|
||||
title: {
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
left: TITLE_OFFSET,
|
||||
right: TITLE_OFFSET,
|
||||
position: 'absolute',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
justifyContent: Platform.OS === 'ios' ? 'center' : 'flex-start',
|
||||
},
|
||||
left: {
|
||||
left: 0,
|
||||
|
||||
@@ -62,9 +62,38 @@ class HeaderBackButton extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { onPress, pressColorAndroid, layoutPreset, title } = this.props;
|
||||
|
||||
let button = (
|
||||
<TouchableItem
|
||||
accessibilityComponentType="button"
|
||||
accessibilityLabel={title}
|
||||
accessibilityTraits="button"
|
||||
testID="header-back"
|
||||
delayPressIn={0}
|
||||
onPress={onPress}
|
||||
pressColor={pressColorAndroid}
|
||||
style={styles.container}
|
||||
borderless
|
||||
>
|
||||
<View style={styles.container}>
|
||||
{this._renderBackImage()}
|
||||
{this._maybeRenderTitle()}
|
||||
</View>
|
||||
</TouchableItem>
|
||||
);
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
return <View style={styles.androidButtonWrapper}>{button}</View>;
|
||||
} else {
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
||||
_maybeRenderTitle() {
|
||||
const {
|
||||
onPress,
|
||||
pressColorAndroid,
|
||||
layoutPreset,
|
||||
backTitleVisible,
|
||||
width,
|
||||
title,
|
||||
titleStyle,
|
||||
@@ -79,41 +108,35 @@ class HeaderBackButton extends React.PureComponent {
|
||||
|
||||
const backButtonTitle = renderTruncated ? truncatedTitle : title;
|
||||
|
||||
// If the left preset is used and we aren't on Android, then we
|
||||
// default to disabling the label
|
||||
const titleDefaultsToDisabled =
|
||||
layoutPreset === 'left' ||
|
||||
Platform.OS === 'android' ||
|
||||
typeof backButtonTitle !== 'string';
|
||||
|
||||
// If the title is explicitly enabled then we respect that
|
||||
if (titleDefaultsToDisabled && !backTitleVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableItem
|
||||
accessibilityComponentType="button"
|
||||
accessibilityLabel={backButtonTitle}
|
||||
accessibilityTraits="button"
|
||||
testID="header-back"
|
||||
delayPressIn={0}
|
||||
onPress={onPress}
|
||||
pressColor={pressColorAndroid}
|
||||
style={styles.container}
|
||||
borderless
|
||||
<Text
|
||||
onLayout={this._onTextLayout}
|
||||
style={[styles.title, !!tintColor && { color: tintColor }, titleStyle]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
{this._renderBackImage()}
|
||||
{Platform.OS === 'ios' &&
|
||||
typeof backButtonTitle === 'string' && (
|
||||
<Text
|
||||
onLayout={this._onTextLayout}
|
||||
style={[
|
||||
styles.title,
|
||||
!!tintColor && { color: tintColor },
|
||||
titleStyle,
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{backButtonTitle}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</TouchableItem>
|
||||
{backButtonTitle}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
androidButtonWrapper: {
|
||||
margin: 13,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
@@ -137,7 +160,7 @@ const styles = StyleSheet.create({
|
||||
: {
|
||||
height: 24,
|
||||
width: 24,
|
||||
margin: 16,
|
||||
margin: 3,
|
||||
resizeMode: 'contain',
|
||||
transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }],
|
||||
},
|
||||
|
||||
@@ -17,7 +17,6 @@ const styles = StyleSheet.create({
|
||||
fontSize: Platform.OS === 'ios' ? 17 : 20,
|
||||
fontWeight: Platform.OS === 'ios' ? '700' : '500',
|
||||
color: 'rgba(0, 0, 0, .9)',
|
||||
textAlign: Platform.OS === 'ios' ? 'center' : 'left',
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -133,23 +133,23 @@ export default function ScenesReducer(
|
||||
|
||||
// We can get into a weird place where we have a queued transition and then clobber
|
||||
// that transition without ever actually rendering the scene, in which case
|
||||
// there is no lastScene and so we need to grab the descriptor from elsewhere.
|
||||
// Warning: changes to descriptor caching may break this, and in that case
|
||||
// we may be better off just not adding it to stale scenes at all.
|
||||
// there is no lastScene. If the descriptor is not available on the lastScene
|
||||
// or the descriptors prop then we just skip adding it to stale scenes and it's
|
||||
// not ever rendered.
|
||||
const descriptor = lastScene
|
||||
? lastScene.descriptor
|
||||
: descriptors[route.key];
|
||||
|
||||
invariant(descriptor, 'Cannot add stale scene with no descriptor');
|
||||
|
||||
staleScenes.set(key, {
|
||||
index,
|
||||
isActive: false,
|
||||
isStale: true,
|
||||
key,
|
||||
route,
|
||||
descriptor,
|
||||
});
|
||||
if (descriptor) {
|
||||
staleScenes.set(key, {
|
||||
index,
|
||||
isActive: false,
|
||||
isStale: true,
|
||||
key,
|
||||
route,
|
||||
descriptor,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,12 @@ const IS_IPHONE_X =
|
||||
|
||||
const EaseInOut = Easing.inOut(Easing.ease);
|
||||
|
||||
/**
|
||||
* Enumerate possible values for validation
|
||||
*/
|
||||
const HEADER_LAYOUT_PRESET_VALUES = ['center', 'left'];
|
||||
const HEADER_TRANSITION_PRESET_VALUES = ['uikit', 'fade-in-place'];
|
||||
|
||||
/**
|
||||
* The max duration of the card animation in milliseconds after released gesture.
|
||||
* The actual duration should be always less then that because the rest distance
|
||||
@@ -159,6 +165,8 @@ class StackViewLayout extends React.Component {
|
||||
scene,
|
||||
mode: headerMode,
|
||||
transitionPreset: this._getHeaderTransitionPreset(),
|
||||
layoutPreset: this._getHeaderLayoutPreset(),
|
||||
backTitleVisible: this._getheaderBackTitleVisible(),
|
||||
leftInterpolator: headerLeftInterpolator,
|
||||
titleInterpolator: headerTitleInterpolator,
|
||||
rightInterpolator: headerRightInterpolator,
|
||||
@@ -477,6 +485,40 @@ class StackViewLayout extends React.Component {
|
||||
return 'float';
|
||||
}
|
||||
|
||||
_getHeaderLayoutPreset() {
|
||||
const { headerLayoutPreset } = this.props;
|
||||
if (headerLayoutPreset) {
|
||||
if (__DEV__) {
|
||||
if (
|
||||
this._getHeaderTransitionPreset() === 'uitkit' &&
|
||||
headerLayoutPreset === 'left' &&
|
||||
Platform.OS === 'ios'
|
||||
) {
|
||||
console.warn(
|
||||
`headerTransitionPreset with the value 'ui-kit' is incompatible with headerLayoutPreset 'left'`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (HEADER_LAYOUT_PRESET_VALUES.includes(headerLayoutPreset)) {
|
||||
return headerLayoutPreset;
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
console.error(
|
||||
`Invalid configuration applied for headerLayoutPreset - expected one of ${HEADER_LAYOUT_PRESET_VALUES.join(
|
||||
', '
|
||||
)} but received ${JSON.stringify(headerLayoutPreset)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
return 'left';
|
||||
} else {
|
||||
return 'center';
|
||||
}
|
||||
}
|
||||
|
||||
_getHeaderTransitionPreset() {
|
||||
// On Android or with header mode screen, we always just use in-place,
|
||||
// we ignore the option entirely (at least until we have other presets)
|
||||
@@ -484,12 +526,28 @@ class StackViewLayout extends React.Component {
|
||||
return 'fade-in-place';
|
||||
}
|
||||
|
||||
// TODO: validations: 'fade-in-place' or 'uikit' are valid
|
||||
if (this.props.headerTransitionPreset) {
|
||||
return this.props.headerTransitionPreset;
|
||||
} else {
|
||||
return 'fade-in-place';
|
||||
const { headerTransitionPreset } = this.props;
|
||||
if (headerTransitionPreset) {
|
||||
if (HEADER_TRANSITION_PRESET_VALUES.includes(headerTransitionPreset)) {
|
||||
return headerTransitionPreset;
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
console.error(
|
||||
`Invalid configuration applied for headerTransitionPreset - expected one of ${HEADER_TRANSITION_PRESET_VALUES.join(
|
||||
', '
|
||||
)} but received ${JSON.stringify(headerTransitionPreset)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return 'fade-in-place';
|
||||
}
|
||||
|
||||
_getheaderBackTitleVisible() {
|
||||
const { headerBackTitleVisible } = this.props;
|
||||
|
||||
return headerBackTitleVisible;
|
||||
}
|
||||
|
||||
_renderInnerScene(scene) {
|
||||
|
||||
Reference in New Issue
Block a user