mirror of
https://github.com/status-im/react-navigation.git
synced 2025-02-24 17:18:09 +00:00
[iOS 11] Handle landscape tabbar correctly. (#2676)
* Handle the ios11 tabbar correctly * Fix an issue when showLabel is false * Add a basic test for the tabbarbottom * Add check for ios version number * Tests shall pass * make things work for all the versions * Again, fix the tests
This commit is contained in:
parent
82c2cdbe09
commit
36ffc4f31a
@ -1,8 +1,15 @@
|
||||
/* @flow */
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Animated, TouchableWithoutFeedback, StyleSheet } from 'react-native';
|
||||
import {
|
||||
Animated,
|
||||
TouchableWithoutFeedback,
|
||||
StyleSheet,
|
||||
View,
|
||||
Platform,
|
||||
} from 'react-native';
|
||||
import TabBarIcon from './TabBarIcon';
|
||||
import withOrientation from '../withOrientation';
|
||||
|
||||
import type {
|
||||
NavigationAction,
|
||||
@ -45,13 +52,13 @@ type Props = {
|
||||
style?: ViewStyleProp,
|
||||
labelStyle?: TextStyleProp,
|
||||
tabStyle?: ViewStyleProp,
|
||||
showIcon?: boolean,
|
||||
isLandscape?: boolean,
|
||||
};
|
||||
|
||||
export default class TabBarBottom extends PureComponent<
|
||||
DefaultProps,
|
||||
Props,
|
||||
void
|
||||
> {
|
||||
const majorVersionIOS = parseInt(Platform.Version, 10);
|
||||
|
||||
class TabBarBottom extends PureComponent<DefaultProps, Props, void> {
|
||||
// See https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/UIKitUICatalog/UITabBar.html
|
||||
static defaultProps: DefaultProps = {
|
||||
activeTintColor: '#3478f6', // Default active tint color in iOS 10
|
||||
@ -73,6 +80,8 @@ export default class TabBarBottom extends PureComponent<
|
||||
inactiveTintColor,
|
||||
labelStyle,
|
||||
showLabel,
|
||||
showIcon,
|
||||
isLandscape,
|
||||
allowFontScaling,
|
||||
} = this.props;
|
||||
if (showLabel === false) {
|
||||
@ -93,10 +102,19 @@ export default class TabBarBottom extends PureComponent<
|
||||
|
||||
const tintColor = scene.focused ? activeTintColor : inactiveTintColor;
|
||||
const label = this.props.getLabel({ ...scene, tintColor });
|
||||
let marginLeft = 0;
|
||||
if (isLandscape && showIcon && majorVersionIOS >= 11) {
|
||||
marginLeft = LABEL_LEFT_MARGIN;
|
||||
}
|
||||
let marginTop = 0;
|
||||
if (!isLandscape && showIcon && majorVersionIOS >= 11) {
|
||||
marginTop = LABEL_TOP_MARGIN;
|
||||
}
|
||||
|
||||
if (typeof label === 'string') {
|
||||
return (
|
||||
<Animated.Text
|
||||
style={[styles.label, { color }, labelStyle]}
|
||||
style={[styles.label, { color, marginLeft, marginTop }, labelStyle]}
|
||||
allowFontScaling={allowFontScaling}
|
||||
>
|
||||
{label}
|
||||
@ -119,6 +137,7 @@ export default class TabBarBottom extends PureComponent<
|
||||
inactiveTintColor,
|
||||
renderIcon,
|
||||
showIcon,
|
||||
showLabel,
|
||||
} = this.props;
|
||||
if (showIcon === false) {
|
||||
return null;
|
||||
@ -131,7 +150,7 @@ export default class TabBarBottom extends PureComponent<
|
||||
inactiveTintColor={inactiveTintColor}
|
||||
renderIcon={renderIcon}
|
||||
scene={scene}
|
||||
style={styles.icon}
|
||||
style={showLabel && majorVersionIOS >= 11 ? {} : styles.icon}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -153,6 +172,7 @@ export default class TabBarBottom extends PureComponent<
|
||||
inactiveBackgroundColor,
|
||||
style,
|
||||
tabStyle,
|
||||
isLandscape,
|
||||
} = this.props;
|
||||
const { routes } = navigation.state;
|
||||
// Prepend '-1', so there are always at least 2 items in inputRange
|
||||
@ -173,9 +193,11 @@ export default class TabBarBottom extends PureComponent<
|
||||
inputRange,
|
||||
outputRange: (outputRange: Array<string>),
|
||||
});
|
||||
|
||||
const justifyContent = this.props.showIcon ? 'flex-end' : 'center';
|
||||
const extraProps = this._renderTestIDProps(scene) || {};
|
||||
const { testID, accessibilityLabel } = extraProps;
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback
|
||||
key={route.key}
|
||||
@ -187,7 +209,9 @@ export default class TabBarBottom extends PureComponent<
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.tab,
|
||||
{ backgroundColor, justifyContent },
|
||||
isLandscape && majorVersionIOS >= 11 && styles.tabLandscape,
|
||||
!isLandscape && majorVersionIOS >= 11 && styles.tabPortrait,
|
||||
{ backgroundColor },
|
||||
tabStyle,
|
||||
]}
|
||||
>
|
||||
@ -202,19 +226,29 @@ export default class TabBarBottom extends PureComponent<
|
||||
}
|
||||
}
|
||||
|
||||
const LABEL_LEFT_MARGIN = 20;
|
||||
const LABEL_TOP_MARGIN = 15;
|
||||
const styles = StyleSheet.create({
|
||||
tabBar: {
|
||||
height: 49, // Default tab bar height in iOS 10
|
||||
height: 49, // Default tab bar height in iOS 10+
|
||||
flexDirection: 'row',
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: 'rgba(0, 0, 0, .3)',
|
||||
backgroundColor: '#F7F7F7', // Default background color in iOS 10
|
||||
backgroundColor: '#F7F7F7', // Default background color in iOS 10+
|
||||
},
|
||||
tab: {
|
||||
flex: 1,
|
||||
alignItems: 'stretch',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
tabPortrait: {
|
||||
justifyContent: 'flex-end',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
tabLandscape: {
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
icon: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
@ -225,3 +259,5 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
});
|
||||
|
||||
export default withOrientation(TabBarBottom);
|
||||
|
31
src/views/__tests__/TabView-test.js
Normal file
31
src/views/__tests__/TabView-test.js
Normal file
@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import renderer from 'react-test-renderer';
|
||||
import TabRouter from '../../routers/TabRouter';
|
||||
|
||||
import TabView from '../TabView/TabView';
|
||||
import TabBarBottom from '../TabView/TabBarBottom';
|
||||
|
||||
describe('TabBarBottom', () => {
|
||||
it('renders successfully', () => {
|
||||
const navigation = {
|
||||
state: {
|
||||
index: 0,
|
||||
routes: [{ key: 's1', routeName: 's1' }],
|
||||
},
|
||||
};
|
||||
const router = TabRouter({ s1: { screen: View } });
|
||||
|
||||
const rendered = renderer
|
||||
.create(
|
||||
<TabView
|
||||
tabBarComponent={TabBarBottom}
|
||||
navigation={navigation}
|
||||
router={router}
|
||||
/>
|
||||
)
|
||||
.toJSON();
|
||||
|
||||
expect(rendered).toMatchSnapshot();
|
||||
});
|
||||
});
|
228
src/views/__tests__/__snapshots__/TabView-test.js.snap
Normal file
228
src/views/__tests__/__snapshots__/TabView-test.js.snap
Normal file
@ -0,0 +1,228 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TabBarBottom renders successfully 1`] = `
|
||||
<View
|
||||
loaded={
|
||||
Array [
|
||||
0,
|
||||
]
|
||||
}
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
},
|
||||
Object {
|
||||
"flex": 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
collapsable={undefined}
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#F7F7F7",
|
||||
"borderTopColor": "rgba(0, 0, 0, .3)",
|
||||
"borderTopWidth": 0.5,
|
||||
"flexDirection": "row",
|
||||
"height": 49,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
accessibilityComponentType={undefined}
|
||||
accessibilityLabel={undefined}
|
||||
accessibilityTraits={undefined}
|
||||
accessible={true}
|
||||
collapsable={undefined}
|
||||
hitSlop={undefined}
|
||||
nativeID={undefined}
|
||||
onLayout={undefined}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderMove={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={[Function]}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "rgba(0, 0, 0, 0)",
|
||||
"flex": 1,
|
||||
"justifyContent": "flex-end",
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<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}
|
||||
disabled={false}
|
||||
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>
|
||||
<RCTScrollView
|
||||
DEPRECATED_sendUpdatedChildFrames={false}
|
||||
alwaysBounceHorizontal={false}
|
||||
alwaysBounceVertical={false}
|
||||
automaticallyAdjustContentInsets={false}
|
||||
bounces={false}
|
||||
contentContainerStyle={
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
}
|
||||
}
|
||||
contentOffset={
|
||||
Object {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
}
|
||||
}
|
||||
directionalLockEnabled={true}
|
||||
horizontal={true}
|
||||
keyboardDismissMode="on-drag"
|
||||
keyboardShouldPersistTaps="always"
|
||||
onContentSizeChange={null}
|
||||
onMomentumScrollBegin={[Function]}
|
||||
onMomentumScrollEnd={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderReject={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={undefined}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onScroll={[Function]}
|
||||
onScrollBeginDrag={[Function]}
|
||||
onScrollEndDrag={[Function]}
|
||||
onScrollShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponderCapture={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
pagingEnabled={true}
|
||||
scrollEnabled={undefined}
|
||||
scrollEventThrottle={16}
|
||||
scrollsToTop={false}
|
||||
sendMomentumEvents={true}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"flexGrow": 1,
|
||||
"flexShrink": 1,
|
||||
"overflow": "scroll",
|
||||
},
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<RCTScrollContentView
|
||||
collapsable={false}
|
||||
removeClippedSubviews={undefined}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
},
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flex": 1,
|
||||
"overflow": "hidden",
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
navigation={
|
||||
Object {
|
||||
"goBack": [Function],
|
||||
"navigate": [Function],
|
||||
"setParams": [Function],
|
||||
"state": Object {
|
||||
"key": "s1",
|
||||
"routeName": "s1",
|
||||
},
|
||||
}
|
||||
}
|
||||
screenProps={undefined}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</RCTScrollContentView>
|
||||
</RCTScrollView>
|
||||
</View>
|
||||
`;
|
Loading…
x
Reference in New Issue
Block a user