From ccb2d380891a3dfbfbeca17de0bd6c4501c4fe08 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Sun, 31 Mar 2019 00:05:50 +0100 Subject: [PATCH] feat: hide tab bar when keyboard is shown (#112) Closes #16 When the statusbar is not translucent, the view resizes when the keyboard is shown on Android. The tab bar stays above the keyboard. This PR makes the tab bar hide automatically when the keyboard is shown. The behaviour is enabled by default and can be disabled with `keyboardHidesTabBar: false` in `tabBarOptions` --- .../bottom-tabs/src/views/BottomTabBar.js | 193 +++++++++++++----- 1 file changed, 139 insertions(+), 54 deletions(-) diff --git a/packages/bottom-tabs/src/views/BottomTabBar.js b/packages/bottom-tabs/src/views/BottomTabBar.js index 2a00d049..2179ce7f 100644 --- a/packages/bottom-tabs/src/views/BottomTabBar.js +++ b/packages/bottom-tabs/src/views/BottomTabBar.js @@ -2,18 +2,20 @@ import React from 'react'; import { + Animated, TouchableWithoutFeedback, StyleSheet, View, + Keyboard, Platform, } from 'react-native'; import { SafeAreaView } from '@react-navigation/native'; -import Animated from 'react-native-reanimated'; import CrossFadeIcon from './CrossFadeIcon'; import withDimensions from '../utils/withDimensions'; export type TabBarOptions = { + keyboardHidesTabBar: boolean, activeTintColor?: string, inactiveTintColor?: string, activeBackgroundColor?: string, @@ -45,6 +47,12 @@ type Props = TabBarOptions & { safeAreaInset: { top: string, right: string, bottom: string, left: string }, }; +type State = { + layout: { height: number, width: number }, + keyboard: boolean, + visible: Animated.Value, +}; + const majorVersion = parseInt(Platform.Version, 10); const isIos = Platform.OS === 'ios'; const isIOS11 = majorVersion >= 11 && isIos; @@ -79,8 +87,9 @@ class TouchableWithoutFeedbackWrapper extends React.Component<*> { } } -class TabBarBottom extends React.Component { +class TabBarBottom extends React.Component { static defaultProps = { + keyboardHidesTabBar: true, activeTintColor: '#007AFF', activeBackgroundColor: 'transparent', inactiveTintColor: '#8E8E93', @@ -92,6 +101,66 @@ class TabBarBottom extends React.Component { safeAreaInset: { bottom: 'always', top: 'never' }, }; + state = { + layout: { height: 0, width: 0 }, + keyboard: false, + visible: new Animated.Value(1), + }; + + componentDidMount() { + if (Platform.OS === 'ios') { + Keyboard.addListener('keyboardWillShow', this._handleKeyboardShow); + Keyboard.addListener('keyboardWillHide', this._handleKeyboardHide); + } else { + Keyboard.addListener('keyboardDidShow', this._handleKeyboardShow); + Keyboard.addListener('keyboardDidHide', this._handleKeyboardHide); + } + } + + componentWillUnmount() { + if (Platform.OS === 'ios') { + Keyboard.removeListener('keyboardWillShow', this._handleKeyboardShow); + Keyboard.removeListener('keyboardWillHide', this._handleKeyboardHide); + } else { + Keyboard.removeListener('keyboardDidShow', this._handleKeyboardShow); + Keyboard.removeListener('keyboardDidHide', this._handleKeyboardHide); + } + } + + _handleKeyboardShow = () => + this.setState({ keyboard: true }, () => + Animated.timing(this.state.visible, { + toValue: 0, + duration: 150, + useNativeDriver: true, + }).start() + ); + + _handleKeyboardHide = () => + Animated.timing(this.state.visible, { + toValue: 1, + duration: 100, + useNativeDriver: true, + }).start(() => { + this.setState({ keyboard: false }); + }); + + _handleLayout = e => { + const { layout } = this.state; + const { height, width } = e.nativeEvent.layout; + + if (height === layout.height && width === layout.width) { + return; + } + + this.setState({ + layout: { + height, + width, + }, + }); + }; + _renderLabel = ({ route, focused }) => { const { activeTintColor, @@ -202,6 +271,7 @@ class TabBarBottom extends React.Component { render() { const { navigation, + keyboardHidesTabBar, activeBackgroundColor, inactiveBackgroundColor, onTabPress, @@ -222,62 +292,71 @@ class TabBarBottom extends React.Component { ]; return ( - - {routes.map((route, index) => { - const focused = index === navigation.state.index; - const scene = { route, focused }; - - const accessibilityLabel = this.props.getAccessibilityLabel({ - route, - }); - - const accessibilityRole = - this.props.getAccessibilityRole({ + + ); } } @@ -292,6 +371,12 @@ const styles = StyleSheet.create({ borderTopColor: 'rgba(0, 0, 0, .3)', flexDirection: 'row', }, + container: { + left: 0, + right: 0, + bottom: 0, + elevation: 8, + }, tabBarCompact: { height: COMPACT_HEIGHT, },