Reworked headerBackImage navigation prop and rendering (#3680)

* Added possibility to provide custom header back button's image, introduced API changes: removed old prop "headerBackImage", added new prop "backImage".

* Code style fixes.

* Renamed showcase file to for more clarity; updated the prop's name as well.

* Removed listeners code from showcase screens.
This commit is contained in:
spaceye 2018-03-13 23:15:11 +03:00 committed by Brent Vatne
parent c2e197f8d3
commit d017ed01b3
7 changed files with 218 additions and 29 deletions

View File

@ -27,6 +27,7 @@ import ModalStack from './ModalStack';
import StacksInTabs from './StacksInTabs';
import StacksOverTabs from './StacksOverTabs';
import StacksWithKeys from './StacksWithKeys';
import StackWithCustomHeaderBackImage from './StackWithCustomHeaderBackImage';
import SimpleStack from './SimpleStack';
import StackWithHeaderPreset from './StackWithHeaderPreset';
import StackWithTranslucentHeader from './StackWithTranslucentHeader';
@ -39,6 +40,10 @@ const ExampleInfo = {
name: 'Stack Example',
description: 'A card stack',
},
StackWithCustomHeaderBackImage: {
name: 'Custom header back image',
description: 'Stack with custom header back image',
},
SimpleTabs: {
name: 'Tabs Example',
description: 'Tabs following platform conventions',
@ -51,10 +56,6 @@ const ExampleInfo = {
name: 'UIKit-style Header Transitions',
description: 'Masked back button and sliding header items. iOS only.',
},
StackWithHeaderPreset: {
name: 'UIKit-style Header Transitions',
description: 'Masked back button and sliding header items. iOS only.',
},
StackWithTranslucentHeader: {
name: 'Translucent Header',
description: 'Render arbitrary translucent content in header background.',
@ -122,6 +123,7 @@ const ExampleRoutes = {
// MultipleDrawer: {
// screen: MultipleDrawer,
// },
StackWithCustomHeaderBackImage: StackWithCustomHeaderBackImage,
StackWithHeaderPreset: StackWithHeaderPreset,
StackWithTranslucentHeader: StackWithTranslucentHeader,
TabsInDrawer: TabsInDrawer,

View File

@ -0,0 +1,145 @@
/**
* @flow
*/
import type { NavigationScreenProp } from 'react-navigation';
import * as React from 'react';
import { Image, Button, StatusBar, StyleSheet } from 'react-native';
import { StackNavigator, SafeAreaView } from 'react-navigation';
import SampleText from './SampleText';
type MyNavScreenProps = {
navigation: NavigationScreenProp<*>,
banner: React.Node,
};
class MyCustomHeaderBackImage extends React.Component<any, any> {
render() {
const source = require('./assets/back.png');
return (
<Image
source={source}
style={[styles.myCustomHeaderBackImage, this.props.style]}
/>
);
}
}
class MyNavScreen extends React.Component<MyNavScreenProps> {
render() {
const { navigation, banner } = this.props;
return (
<SafeAreaView>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
title="Navigate to a photos screen"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);
}
}
type MyHomeScreenProps = {
navigation: NavigationScreenProp<*>,
};
class MyHomeScreen extends React.Component<MyHomeScreenProps> {
static navigationOptions = {
title: 'Welcome',
headerBackTitle: null,
};
render() {
const { navigation } = this.props;
return <MyNavScreen banner="Home Screen" navigation={navigation} />;
}
}
type MyPhotosScreenProps = {
navigation: NavigationScreenProp<*>,
};
class MyPhotosScreen extends React.Component<MyPhotosScreenProps> {
static navigationOptions = ({ navigation }) => ({
title: `${navigation.state.params.name}'s photos`,
headerBackTitle: null,
});
render() {
const { navigation } = this.props;
return (
<SafeAreaView>
<SampleText>{`${navigation.state.params.name}'s Photos`}</SampleText>
<Button
onPress={() => navigation.navigate('Profile', { name: 'Jane' })}
title="Navigate to a profile screen"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);
}
}
type MyProfileScreenProps = {
navigation: NavigationScreenProp<*>,
};
class MyProfileScreen extends React.Component<MyProfileScreenProps> {
static navigationOptions = ({ navigation }) => ({
title: 'Profile',
headerBackImage: (
<MyCustomHeaderBackImage style={styles.myCustomHeaderBackImageAlt} />
),
});
render() {
const { navigation } = this.props;
return (
<SafeAreaView>
<SampleText>{`${navigation.state.params.name}'s Profile`}</SampleText>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);
}
}
const StackWithCustomHeaderBackImage = StackNavigator(
{
Home: {
screen: MyHomeScreen,
},
Photos: {
path: 'photos/:name',
screen: MyPhotosScreen,
},
Profile: {
path: 'profile/:name',
screen: MyProfileScreen,
},
},
{
navigationOptions: {
headerBackImage: MyCustomHeaderBackImage,
},
}
);
export default StackWithCustomHeaderBackImage;
const styles = StyleSheet.create({
myCustomHeaderBackImage: {
height: 14.5,
width: 24,
marginLeft: 9,
marginRight: 12,
marginVertical: 12,
resizeMode: 'contain',
},
myCustomHeaderBackImageAlt: {
tintColor: '#f00',
},
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -343,7 +343,7 @@ declare module 'react-navigation' {
headerTintColor?: string,
headerLeft?: React$Node | React$ElementType,
headerBackTitle?: string,
headerBackImage?: ImageSource,
headerBackImage?: React$Node | React$ElementType,
headerTruncatedBackTitle?: string,
headerBackTitleStyle?: TextStyleProp,
headerPressColorAndroid?: string,

View File

@ -151,7 +151,7 @@ class Header extends React.PureComponent {
onPress={goBack}
pressColorAndroid={options.headerPressColorAndroid}
tintColor={options.headerTintColor}
buttonImage={options.headerBackImage}
backImage={options.headerBackImage}
title={backButtonTitle}
truncatedTitle={truncatedBackButtonTitle}
titleStyle={options.headerBackTitleStyle}
@ -181,7 +181,7 @@ class Header extends React.PureComponent {
LabelContainerComponent={LabelContainerComponent}
pressColorAndroid={options.headerPressColorAndroid}
tintColor={options.headerTintColor}
buttonImage={options.headerBackImage}
backImage={options.headerBackImage}
title={backButtonTitle}
truncatedTitle={truncatedBackButtonTitle}
titleStyle={options.headerBackTitleStyle}

View File

@ -10,6 +10,8 @@ import {
import TouchableItem from '../TouchableItem';
const defaultBackImage = require('../assets/back-icon.png');
class HeaderBackButton extends React.PureComponent {
static defaultProps = {
pressColorAndroid: 'rgba(0, 0, 0, .32)',
@ -17,8 +19,6 @@ class HeaderBackButton extends React.PureComponent {
ios: '#037aff',
}),
truncatedTitle: 'Back',
// eslint-disable-next-line global-require
buttonImage: require('../assets/back-icon.png'),
};
state = {};
@ -32,9 +32,37 @@ class HeaderBackButton extends React.PureComponent {
});
};
_renderBackImage() {
const { backImage, title, tintColor } = this.props;
let BackImage;
let props;
if (React.isValidElement(backImage)) {
return backImage;
} else if (backImage) {
BackImage = backImage;
props = {
tintColor,
title,
};
} else {
BackImage = Image;
props = {
style: [
styles.icon,
!!title && styles.iconWithTitle,
!!tintColor && { tintColor },
],
source: defaultBackImage,
};
}
return <BackImage {...props} />;
}
render() {
const {
buttonImage,
onPress,
pressColorAndroid,
width,
@ -64,14 +92,7 @@ class HeaderBackButton extends React.PureComponent {
borderless
>
<View style={styles.container}>
<Image
style={[
styles.icon,
!!title && styles.iconWithTitle,
!!tintColor && { tintColor },
]}
source={buttonImage}
/>
{this._renderBackImage()}
{Platform.OS === 'ios' &&
typeof backButtonTitle === 'string' && (
<Text

View File

@ -3,12 +3,12 @@ import { I18nManager, Image, Text, View, StyleSheet } from 'react-native';
import TouchableItem from '../TouchableItem';
const defaultBackImage = require('../assets/back-icon.png');
class ModularHeaderBackButton extends React.PureComponent {
static defaultProps = {
tintColor: '#037aff',
truncatedTitle: 'Back',
// eslint-disable-next-line global-require
buttonImage: require('../assets/back-icon.png'),
};
state = {};
@ -22,9 +22,37 @@ class ModularHeaderBackButton extends React.PureComponent {
});
};
_renderBackImage() {
const { backImage, title, tintColor } = this.props;
let BackImage;
let props;
if (React.isValidElement(backImage)) {
return backImage;
} else if (backImage) {
BackImage = backImage;
props = {
tintColor,
title,
};
} else {
BackImage = Image;
props = {
style: [
styles.icon,
!!title && styles.iconWithTitle,
!!tintColor && { tintColor },
],
source: defaultBackImage,
};
}
return <BackImage {...props} />;
}
render() {
const {
buttonImage,
onPress,
width,
title,
@ -61,14 +89,7 @@ class ModularHeaderBackButton extends React.PureComponent {
>
<View style={styles.container}>
<ButtonContainerComponent>
<Image
style={[
styles.icon,
!!title && styles.iconWithTitle,
!!tintColor && { tintColor },
]}
source={buttonImage}
/>
{this._renderBackImage()}
</ButtonContainerComponent>
{typeof backButtonTitle === 'string' && (
<LabelContainerComponent>