[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:
Spencer Carli 2017-10-16 04:01:30 -05:00 committed by Lorenzo Sciandra
parent 82c2cdbe09
commit 36ffc4f31a
3 changed files with 307 additions and 12 deletions

View File

@ -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);

View 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();
});
});

View 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>
`;