From 08a626886e1d523908af2426d709fc35fe331759 Mon Sep 17 00:00:00 2001 From: Adrian Hartanto Date: Thu, 31 Oct 2019 21:14:45 +0800 Subject: [PATCH] feat: add keyboardHidesTabBarAnimationConfig props (#195) --- src/types.tsx | 41 +++++++++++++++++++ src/views/BottomTabBar.tsx | 81 ++++++++++++++++++++++++++++++++------ 2 files changed, 110 insertions(+), 12 deletions(-) diff --git a/src/types.tsx b/src/types.tsx index c029c422f..c2669f34a 100644 --- a/src/types.tsx +++ b/src/types.tsx @@ -38,8 +38,49 @@ export type Orientation = 'horizontal' | 'vertical'; export type LabelPosition = 'beside-icon' | 'below-icon'; +interface BaseAnimation { + useNativeDriver?: boolean; +} +interface TimingAnimation extends BaseAnimation { + easing?: (value: number) => number; + duration?: number; + delay?: number; +} +interface SpringAnimation extends BaseAnimation { + overshootClamping?: boolean; + restDisplacementThreshold?: number; + restSpeedThreshold?: number; + velocity?: number | { x: number; y: number }; + bounciness?: number; + speed?: number; + tension?: number; + friction?: number; + stiffness?: number; + mass?: number; + damping?: number; + delay?: number; +} +export type TimingKeyboardAnimationConfig = { + animation: 'timing'; + config?: TimingAnimation; +}; +export type SpringKeyboardAnimationConfig = { + animation: 'spring'; + config?: SpringAnimation; +}; +export type KeyboardAnimationConfig = + | TimingKeyboardAnimationConfig + | SpringKeyboardAnimationConfig; +export type KeyboardHidesTabBarAnimationConfig = { + show: KeyboardAnimationConfig; + hide: KeyboardAnimationConfig; +}; + export type BottomTabBarOptions = { keyboardHidesTabBar?: boolean; + keyboardHidesTabBarAnimationConfig?: Partial< + KeyboardHidesTabBarAnimationConfig + >; activeTintColor?: ThemedColor; inactiveTintColor?: ThemedColor; activeBackgroundColor?: ThemedColor; diff --git a/src/views/BottomTabBar.tsx b/src/views/BottomTabBar.tsx index 6838d6911..f5450e33e 100644 --- a/src/views/BottomTabBar.tsx +++ b/src/views/BottomTabBar.tsx @@ -13,7 +13,12 @@ import { ThemeColors, ThemeContext, NavigationRoute } from 'react-navigation'; import CrossFadeIcon from './CrossFadeIcon'; import withDimensions from '../utils/withDimensions'; -import { BottomTabBarProps, ButtonComponentProps } from '../types'; +import { + BottomTabBarProps, + ButtonComponentProps, + KeyboardHidesTabBarAnimationConfig, + KeyboardAnimationConfig, +} from '../types'; type State = { layout: { height: number; width: number }; @@ -26,6 +31,22 @@ const isIos = Platform.OS === 'ios'; const isIOS11 = majorVersion >= 11 && isIos; const DEFAULT_MAX_TAB_ITEM_WIDTH = 125; +const DEFAULT_KEYBOARD_ANIMATION_CONFIG: KeyboardHidesTabBarAnimationConfig = { + show: { + animation: 'timing', + config: { + useNativeDriver: true, + duration: 150, + }, + }, + hide: { + animation: 'timing', + config: { + useNativeDriver: true, + duration: 100, + }, + }, +}; class TouchableWithoutFeedbackWrapper extends React.Component< ButtonComponentProps @@ -64,6 +85,7 @@ class TouchableWithoutFeedbackWrapper extends React.Component< class TabBarBottom extends React.Component { static defaultProps = { keyboardHidesTabBar: true, + keyboardHidesTabBarAnimationConfig: DEFAULT_KEYBOARD_ANIMATION_CONFIG, activeTintColor: { light: '#007AFF', dark: '#fff', @@ -115,23 +137,58 @@ class TabBarBottom extends React.Component { // @ts-ignore context: 'light' | 'dark'; - _handleKeyboardShow = () => - this.setState({ keyboard: true }, () => - Animated.timing(this.state.visible, { + _getKeyboardAnimationConfigByType = ( + type: keyof KeyboardHidesTabBarAnimationConfig + ): KeyboardAnimationConfig => { + const { keyboardHidesTabBarAnimationConfig } = this.props; + const defaultKeyboardAnimationConfig = + DEFAULT_KEYBOARD_ANIMATION_CONFIG[type]; + const keyboardAnimationConfig = + (keyboardHidesTabBarAnimationConfig && + keyboardHidesTabBarAnimationConfig[type]) || + defaultKeyboardAnimationConfig; + + // merge config only `timing` animation + if ( + keyboardAnimationConfig && + keyboardAnimationConfig.animation === 'timing' + ) { + return { + ...defaultKeyboardAnimationConfig, + ...keyboardAnimationConfig, + config: { + ...defaultKeyboardAnimationConfig.config, + ...keyboardAnimationConfig.config, + }, + }; + } + + return keyboardAnimationConfig as KeyboardAnimationConfig; + }; + + _handleKeyboardShow = () => { + this.setState({ keyboard: true }, () => { + const { animation, config } = this._getKeyboardAnimationConfigByType( + 'show' + ); + Animated[animation](this.state.visible, { toValue: 0, - duration: 150, - useNativeDriver: true, - }).start() - ); + ...config, + }).start(); + }); + }; - _handleKeyboardHide = () => - Animated.timing(this.state.visible, { + _handleKeyboardHide = () => { + const { animation, config } = this._getKeyboardAnimationConfigByType( + 'hide' + ); + Animated[animation](this.state.visible, { toValue: 1, - duration: 100, - useNativeDriver: true, + ...config, }).start(() => { this.setState({ keyboard: false }); }); + }; _handleLayout = (e: LayoutChangeEvent) => { const { layout } = this.state;