mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-26 05:25:30 +08:00
Compare commits
6 Commits
v1.0.0-bet
...
v1.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abbd88601f | ||
|
|
ff6d6f4e5e | ||
|
|
7fa0ef3aee | ||
|
|
6ac3bb90ed | ||
|
|
627c487936 | ||
|
|
f46bdff703 |
@@ -7,10 +7,9 @@
|
||||
"privacy": "public",
|
||||
"orientation": "portrait",
|
||||
"primaryColor": "#cccccc",
|
||||
"icon": "./assets/icons/react-navigation.png",
|
||||
"loading": {
|
||||
"icon": "./assets/icons/react-navigation.png",
|
||||
"hideExponentText": false
|
||||
"icon": "./assets/icons/icon.png",
|
||||
"splash": {
|
||||
"image": "./assets/icons/splash.png"
|
||||
},
|
||||
"sdkVersion": "24.0.0",
|
||||
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
|
||||
BIN
examples/NavigationPlayground/assets/icons/icon.png
Normal file
BIN
examples/NavigationPlayground/assets/icons/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
BIN
examples/NavigationPlayground/assets/icons/splash.png
Normal file
BIN
examples/NavigationPlayground/assets/icons/splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 145 KiB |
@@ -8,7 +8,7 @@ import { SafeAreaView } from 'react-navigation';
|
||||
const Banner = () => (
|
||||
<SafeAreaView
|
||||
style={styles.bannerContainer}
|
||||
forceInset={{ vertical: 'never' }}
|
||||
forceInset={{ top: 'always' }}
|
||||
>
|
||||
<View style={styles.banner}>
|
||||
<Image source={require('./assets/NavLogo.png')} style={styles.image} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-navigation",
|
||||
"version": "1.0.0-beta.23",
|
||||
"version": "1.0.0-beta.26",
|
||||
"description": "React Navigation",
|
||||
"main": "src/react-navigation.js",
|
||||
"sources": {
|
||||
|
||||
@@ -105,81 +105,68 @@ exports[`TabNavigator renders successfully 1`] = `
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "rgba(0, 0, 0, 0)",
|
||||
"flex": 1,
|
||||
"justifyContent": "flex-end",
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flex": 1,
|
||||
},
|
||||
Object {
|
||||
"flexDirection": "column",
|
||||
"justifyContent": "flex-end",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 1,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<Text
|
||||
accessible={true}
|
||||
allowFontScaling={true}
|
||||
collapsable={undefined}
|
||||
ellipsizeMode="tail"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "transparent",
|
||||
"color": "rgba(52, 120, 246, 1)",
|
||||
"fontSize": 10,
|
||||
"marginBottom": 1.5,
|
||||
"textAlign": "center",
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 1,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
Welcome anonymous
|
||||
</Text>
|
||||
/>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<Text
|
||||
accessible={true}
|
||||
allowFontScaling={true}
|
||||
collapsable={undefined}
|
||||
ellipsizeMode="tail"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "transparent",
|
||||
"color": "rgba(52, 120, 246, 1)",
|
||||
"fontSize": 10,
|
||||
"marginBottom": 1.5,
|
||||
"marginLeft": 0,
|
||||
"marginTop": 0,
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
>
|
||||
Welcome anonymous
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -52,7 +52,26 @@ const isIPad = (() => {
|
||||
return true;
|
||||
})();
|
||||
|
||||
let _customStatusBarHeight = null;
|
||||
const statusBarHeight = isLandscape => {
|
||||
if (_customStatusBarHeight !== null) {
|
||||
return _customStatusBarHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a temporary workaround because we don't have a way to detect
|
||||
* if the status bar is translucent or opaque. If opaque, we don't need to
|
||||
* factor in the height here; if translucent (content renders under it) then
|
||||
* we do.
|
||||
*/
|
||||
if (Platform.OS === 'android') {
|
||||
if (global.Expo) {
|
||||
return global.Expo.Constants.statusBarHeight;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (isIPhoneX) {
|
||||
return isLandscape ? 0 : 44;
|
||||
}
|
||||
@@ -77,6 +96,10 @@ const doubleFromPercentString = percent => {
|
||||
};
|
||||
|
||||
class SafeView extends Component {
|
||||
static setStatusBarHeight = height => {
|
||||
_customStatusBarHeight = height;
|
||||
};
|
||||
|
||||
state = {
|
||||
touchesTop: true,
|
||||
touchesBottom: true,
|
||||
@@ -100,10 +123,6 @@ class SafeView extends Component {
|
||||
render() {
|
||||
const { forceInset = false, isLandscape, children, style } = this.props;
|
||||
|
||||
if (Platform.OS !== 'ios') {
|
||||
return <Animated.View style={style}>{this.props.children}</Animated.View>;
|
||||
}
|
||||
|
||||
const safeAreaStyle = this._getSafeAreaStyle();
|
||||
|
||||
return (
|
||||
|
||||
@@ -8,12 +8,10 @@ import {
|
||||
View,
|
||||
Platform,
|
||||
Keyboard,
|
||||
Dimensions,
|
||||
} from 'react-native';
|
||||
import TabBarIcon from './TabBarIcon';
|
||||
import SafeAreaView from '../SafeAreaView';
|
||||
import withOrientation from '../withOrientation';
|
||||
import type { Layout } from 'react-native-tab-view/src/TabViewTypeDefinitions';
|
||||
|
||||
import type {
|
||||
NavigationRoute,
|
||||
@@ -53,16 +51,11 @@ type Props = {
|
||||
tabStyle?: ViewStyleProp,
|
||||
showIcon?: boolean,
|
||||
isLandscape: boolean,
|
||||
layout: Layout,
|
||||
adaptive: boolean,
|
||||
};
|
||||
|
||||
const majorVersion = parseInt(Platform.Version, 10);
|
||||
const isIos = Platform.OS === 'ios';
|
||||
const isIOS11 = majorVersion >= 11 && isIos;
|
||||
const isTablet =
|
||||
Dimensions.get('window').height / Dimensions.get('window').width < 1.6;
|
||||
const defaultMaxTabBarItemWidth = 125;
|
||||
const useHorizontalTabs = majorVersion >= 11 && isIos;
|
||||
|
||||
class TabBarBottom extends React.PureComponent<Props> {
|
||||
// See https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/UIKitUICatalog/UITabBar.html
|
||||
@@ -74,7 +67,6 @@ class TabBarBottom extends React.PureComponent<Props> {
|
||||
showLabel: true,
|
||||
showIcon: true,
|
||||
allowFontScaling: true,
|
||||
adaptive: isIOS11,
|
||||
};
|
||||
|
||||
_renderLabel = (scene: TabScene) => {
|
||||
@@ -107,18 +99,19 @@ class TabBarBottom extends React.PureComponent<Props> {
|
||||
|
||||
const tintColor = scene.focused ? activeTintColor : inactiveTintColor;
|
||||
const label = this.props.getLabel({ ...scene, tintColor });
|
||||
let marginLeft = 0;
|
||||
if (isLandscape && showIcon && useHorizontalTabs) {
|
||||
marginLeft = LABEL_LEFT_MARGIN;
|
||||
}
|
||||
let marginTop = 0;
|
||||
if (!isLandscape && showIcon && useHorizontalTabs) {
|
||||
marginTop = LABEL_TOP_MARGIN;
|
||||
}
|
||||
|
||||
if (typeof label === 'string') {
|
||||
return (
|
||||
<Animated.Text
|
||||
style={[
|
||||
styles.label,
|
||||
{ color },
|
||||
showIcon && this._shouldUseHorizontalTabs()
|
||||
? styles.labelBeside
|
||||
: styles.labelBeneath,
|
||||
labelStyle,
|
||||
]}
|
||||
style={[styles.label, { color, marginLeft, marginTop }, labelStyle]}
|
||||
allowFontScaling={allowFontScaling}
|
||||
>
|
||||
{label}
|
||||
@@ -154,7 +147,7 @@ class TabBarBottom extends React.PureComponent<Props> {
|
||||
inactiveTintColor={inactiveTintColor}
|
||||
renderIcon={renderIcon}
|
||||
scene={scene}
|
||||
style={showLabel && this._shouldUseHorizontalTabs() ? {} : styles.icon}
|
||||
style={showLabel && useHorizontalTabs ? {} : styles.icon}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -165,65 +158,6 @@ class TabBarBottom extends React.PureComponent<Props> {
|
||||
return testIDProps;
|
||||
};
|
||||
|
||||
_tabItemMaxWidth() {
|
||||
const { tabStyle, layout } = this.props;
|
||||
let maxTabBarItemWidth;
|
||||
|
||||
const flattenedTabStyle = StyleSheet.flatten(tabStyle);
|
||||
|
||||
if (flattenedTabStyle) {
|
||||
if (typeof flattenedTabStyle.width === 'number') {
|
||||
maxTabBarItemWidth = flattenedTabStyle.width;
|
||||
} else if (
|
||||
typeof flattenedTabStyle.width === 'string' &&
|
||||
flattenedTabStyle.endsWith('%')
|
||||
) {
|
||||
const width = parseFloat(flattenedTabStyle.width);
|
||||
if (Number.isFinite(width)) {
|
||||
maxTabBarItemWidth = layout.width * (width / 100);
|
||||
}
|
||||
} else if (typeof flattenedTabStyle.maxWidth === 'number') {
|
||||
maxTabBarItemWidth = flattenedTabStyle.maxWidth;
|
||||
} else if (
|
||||
typeof flattenedTabStyle.maxWidth === 'string' &&
|
||||
flattenedTabStyle.endsWith('%')
|
||||
) {
|
||||
const width = parseFloat(flattenedTabStyle.maxWidth);
|
||||
if (Number.isFinite(width)) {
|
||||
maxTabBarItemWidth = layout.width * (width / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!maxTabBarItemWidth) {
|
||||
maxTabBarItemWidth = defaultMaxTabBarItemWidth;
|
||||
}
|
||||
|
||||
return maxTabBarItemWidth;
|
||||
}
|
||||
|
||||
_shouldUseHorizontalTabs() {
|
||||
const { routes } = this.props.navigation.state;
|
||||
const { isLandscape, layout, adaptive, tabStyle } = this.props;
|
||||
|
||||
if (!adaptive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let tabBarWidth = layout.width;
|
||||
if (tabBarWidth === 0) {
|
||||
return isTablet;
|
||||
}
|
||||
|
||||
const isHeightConstrained = layout.height < 500;
|
||||
if (isHeightConstrained) {
|
||||
return isLandscape;
|
||||
} else {
|
||||
const maxTabBarItemWidth = this._tabItemMaxWidth();
|
||||
return routes.length * maxTabBarItemWidth <= tabBarWidth;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
position,
|
||||
@@ -237,20 +171,17 @@ class TabBarBottom extends React.PureComponent<Props> {
|
||||
animateStyle,
|
||||
tabStyle,
|
||||
isLandscape,
|
||||
layout,
|
||||
} = this.props;
|
||||
const { routes } = navigation.state;
|
||||
const previousScene = routes[navigation.state.index];
|
||||
// Prepend '-1', so there are always at least 2 items in inputRange
|
||||
const inputRange = [-1, ...routes.map((x: *, i: number) => i)];
|
||||
|
||||
const isHeightConstrained =
|
||||
layout.height === 0 ? !isTablet : layout.height < 500;
|
||||
const tabBarStyle = [
|
||||
styles.tabBar,
|
||||
this._shouldUseHorizontalTabs() && isHeightConstrained
|
||||
? styles.tabBarCompact
|
||||
: styles.tabBarRegular,
|
||||
isLandscape && useHorizontalTabs
|
||||
? styles.tabBarLandscape
|
||||
: styles.tabBarPortrait,
|
||||
style,
|
||||
];
|
||||
|
||||
@@ -289,19 +220,17 @@ class TabBarBottom extends React.PureComponent<Props> {
|
||||
? onPress({ previousScene, scene, jumpToIndex })
|
||||
: jumpToIndex(index)}
|
||||
>
|
||||
<Animated.View style={[styles.tab, { backgroundColor }]}>
|
||||
<View
|
||||
style={[
|
||||
styles.tab,
|
||||
this._shouldUseHorizontalTabs()
|
||||
? styles.tabLandscape
|
||||
: styles.tabPortrait,
|
||||
tabStyle,
|
||||
]}
|
||||
>
|
||||
{this._renderIcon(scene)}
|
||||
{this._renderLabel(scene)}
|
||||
</View>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.tab,
|
||||
isLandscape && useHorizontalTabs && styles.tabLandscape,
|
||||
!isLandscape && useHorizontalTabs && styles.tabPortrait,
|
||||
{ backgroundColor },
|
||||
tabStyle,
|
||||
]}
|
||||
>
|
||||
{this._renderIcon(scene)}
|
||||
{this._renderLabel(scene)}
|
||||
</Animated.View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
@@ -312,6 +241,8 @@ class TabBarBottom extends React.PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const LABEL_LEFT_MARGIN = 20;
|
||||
const LABEL_TOP_MARGIN = 15;
|
||||
const styles = StyleSheet.create({
|
||||
tabBar: {
|
||||
backgroundColor: '#F7F7F7', // Default background color in iOS 10
|
||||
@@ -319,15 +250,16 @@ const styles = StyleSheet.create({
|
||||
borderTopColor: 'rgba(0, 0, 0, .3)',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tabBarCompact: {
|
||||
tabBarLandscape: {
|
||||
height: 29,
|
||||
},
|
||||
tabBarRegular: {
|
||||
tabBarPortrait: {
|
||||
height: 49,
|
||||
},
|
||||
tab: {
|
||||
flex: 1,
|
||||
alignItems: isIos ? 'center' : 'stretch',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
tabPortrait: {
|
||||
justifyContent: 'flex-end',
|
||||
@@ -342,15 +274,9 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
label: {
|
||||
textAlign: 'center',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
labelBeneath: {
|
||||
fontSize: 10,
|
||||
marginBottom: 1.5,
|
||||
},
|
||||
labelBeside: {
|
||||
fontSize: 13,
|
||||
marginLeft: 20,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as React from 'react';
|
||||
import { Animated, StyleSheet } from 'react-native';
|
||||
import { TabBar } from 'react-native-tab-view';
|
||||
import TabBarIcon from './TabBarIcon';
|
||||
import SafeAreaView from '../SafeAreaView';
|
||||
|
||||
import type {
|
||||
NavigationAction,
|
||||
@@ -24,6 +25,7 @@ type Props = {
|
||||
upperCaseLabel: boolean,
|
||||
allowFontScaling: boolean,
|
||||
position: Animated.Value,
|
||||
tabBarPosition: string,
|
||||
navigation: NavigationScreenProp<NavigationState>,
|
||||
jumpToIndex: (index: number) => void,
|
||||
getLabel: (scene: TabScene) => ?(React.Node | string),
|
||||
@@ -53,6 +55,7 @@ export default class TabBarTop extends React.PureComponent<Props> {
|
||||
_renderLabel = (scene: TabScene) => {
|
||||
const {
|
||||
position,
|
||||
tabBarPosition,
|
||||
navigation,
|
||||
activeTintColor,
|
||||
inactiveTintColor,
|
||||
@@ -81,12 +84,16 @@ export default class TabBarTop extends React.PureComponent<Props> {
|
||||
const label = this.props.getLabel({ ...scene, tintColor });
|
||||
if (typeof label === 'string') {
|
||||
return (
|
||||
<Animated.Text
|
||||
style={[styles.label, { color }, labelStyle]}
|
||||
allowFontScaling={allowFontScaling}
|
||||
<SafeAreaView
|
||||
forceInset={{ top: tabBarPosition === 'top' ? 'always' : 'never' }}
|
||||
>
|
||||
{upperCaseLabel ? label.toUpperCase() : label}
|
||||
</Animated.Text>
|
||||
<Animated.Text
|
||||
style={[styles.label, { color }, labelStyle]}
|
||||
allowFontScaling={allowFontScaling}
|
||||
>
|
||||
{upperCaseLabel ? label.toUpperCase() : label}
|
||||
</Animated.Text>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
if (typeof label === 'function') {
|
||||
|
||||
@@ -145,10 +145,12 @@ class TabView extends React.PureComponent<Props> {
|
||||
if (typeof TabBarComponent === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<TabBarComponent
|
||||
{...props}
|
||||
{...tabBarOptions}
|
||||
tabBarPosition={this.props.tabBarPosition}
|
||||
screenProps={this.props.screenProps}
|
||||
navigation={this.props.navigation}
|
||||
getLabel={this._getLabel}
|
||||
|
||||
@@ -61,81 +61,68 @@ exports[`TabBarBottom renders successfully 1`] = `
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "rgba(0, 0, 0, 0)",
|
||||
"flex": 1,
|
||||
"justifyContent": "flex-end",
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flex": 1,
|
||||
},
|
||||
Object {
|
||||
"flexDirection": "column",
|
||||
"justifyContent": "flex-end",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 1,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<Text
|
||||
accessible={true}
|
||||
allowFontScaling={true}
|
||||
collapsable={undefined}
|
||||
ellipsizeMode="tail"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "transparent",
|
||||
"color": "rgba(52, 120, 246, 1)",
|
||||
"fontSize": 10,
|
||||
"marginBottom": 1.5,
|
||||
"textAlign": "center",
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 1,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
s1
|
||||
</Text>
|
||||
/>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"bottom": 0,
|
||||
"justifyContent": "center",
|
||||
"left": 0,
|
||||
"opacity": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<Text
|
||||
accessible={true}
|
||||
allowFontScaling={true}
|
||||
collapsable={undefined}
|
||||
ellipsizeMode="tail"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "transparent",
|
||||
"color": "rgba(52, 120, 246, 1)",
|
||||
"fontSize": 10,
|
||||
"marginBottom": 1.5,
|
||||
"marginLeft": 0,
|
||||
"marginTop": 0,
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
>
|
||||
s1
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
Reference in New Issue
Block a user