refactor: updated keyboard handling

This commit is contained in:
Mo Gorhom
2021-03-07 16:50:50 +00:00
parent 8cf924cfc1
commit ce4376d585
5 changed files with 116 additions and 89 deletions

View File

@@ -1,21 +1,11 @@
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable react-native/no-inline-styles */
import React, { useCallback, useMemo, useRef, useState } from 'react';
import {
View,
StyleSheet,
Dimensions,
StatusBar,
Button as RNButton,
} from 'react-native';
import Animated, {
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated';
import { useSafeArea } from 'react-native-safe-area-context';
import { View, StyleSheet, Dimensions, StatusBar } from 'react-native';
import { useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import BottomSheet from '@gorhom/bottom-sheet';
import SearchHandle from './components/searchHandle'
import SearchHandle from './components/searchHandle';
import Button from './components/button';
import ContactList from './components/contactList';
@@ -28,11 +18,11 @@ const BasicExample = () => {
//#region hooks
const bottomSheetRef = useRef<BottomSheet>(null);
const { top: topSafeArea, bottom: bottomSafeArea } = useSafeArea();
const { top: topSafeArea, bottom: bottomSafeArea } = useSafeAreaInsets();
//#endregion
//#region variables
const snapPoints = useMemo(() => [200], [dynamicSnapPoint]);
const snapPoints = useMemo(() => [200, dynamicSnapPoint], [dynamicSnapPoint]);
const animatedPosition = useSharedValue<number>(0);
//#endregion
@@ -97,9 +87,6 @@ const BasicExample = () => {
const handleIncreaseDynamicSnapPoint = useCallback(() => {
setDynamicSnapPoint(state => state + 50);
}, []);
const handleFocus = useCallback(() => {
bottomSheetRef.current.fullScreenExpand();
}, []);
//#endregion
// renders

View File

@@ -6,7 +6,7 @@ import {
NativeSyntheticEvent,
TextInputChangeEventData,
} from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import { BottomSheetTextInput } from '@gorhom/bottom-sheet';
import isEqual from 'lodash.isequal';
import { useAppearance } from '../../hooks';
@@ -48,7 +48,7 @@ const BottomSheetHandleComponent = () => {
return (
<View style={styles.container}>
<View style={indicatorStyle} />
<TextInput
<BottomSheetTextInput
style={styles.input}
value={value}
textContentType="location"

View File

@@ -64,7 +64,6 @@ import {
DEFAULT_ENABLE_OVER_DRAG,
DEFAULT_ENABLE_FLASH_SCROLLABLE_INDICATOR_ON_EXPAND,
DEFAULT_ANIMATE_ON_MOUNT,
DECELERATION_RATE,
DEFAULT_KEYBOARD_BEHAVIOR,
} from './constants';
import type { ScrollableRef, BottomSheetMethods } from '../../types';
@@ -184,7 +183,6 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
// scrollable variables
const {
scrollableContentOffsetY,
scrollableDecelerationRate,
setScrollableRef,
removeScrollableRef,
flashScrollableIndicators,
@@ -198,6 +196,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
height: keyboardHeight,
animationDuration: keyboardAnimationDuration,
animationEasing: keyboardAnimationEasing,
shouldHandleKeyboardEvents,
} = useKeyboard();
// normalize snap points
@@ -297,9 +296,22 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
keyboardBehavior === KEYBOARD_BEHAVIOR.interactive &&
isExtendedByKeyboard.value
) {
return keyboardState.value === KEYBOARD_STATE.SHOWN
? sheetHeight
: sheetHeight + keyboardHeight.value;
const safeFullScreenSheetHeight =
safeContainerHeight - topInset - safeHandleHeight;
const sheetWithKeyboardHeight = sheetHeight + keyboardHeight.value;
if (keyboardState.value === KEYBOARD_STATE.SHOWN) {
if (sheetHeight >= safeFullScreenSheetHeight) {
return safeFullScreenSheetHeight - keyboardHeight.value;
}
return sheetHeight;
}
if (sheetWithKeyboardHeight > safeFullScreenSheetHeight) {
return safeFullScreenSheetHeight;
}
return sheetWithKeyboardHeight;
}
return sheetHeight;
@@ -534,6 +546,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
contentPanGestureHandler,
scrollableState,
scrollableContentOffsetY,
shouldHandleKeyboardEvents,
simultaneousHandlers: _providedSimultaneousHandlers,
waitFor: _providedWaitFor,
activeOffsetX: _providedActiveOffsetX,
@@ -552,6 +565,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
contentPanGestureHandler,
handleSettingScrollableRef,
removeScrollableRef,
shouldHandleKeyboardEvents,
scrollableState,
scrollableContentOffsetY,
enableContentPanningGesture,
@@ -683,7 +697,12 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
state === KEYBOARD_STATE.SHOWN
) {
const newSnapPoint = snapPoints[snapPoints.length - 1];
animateToPoint(newSnapPoint);
animateToPoint(
newSnapPoint,
0,
keyboardAnimationDuration.value,
KEYBOARD_EASING_MAPPER[keyboardAnimationEasing.value]
);
return;
}
@@ -695,41 +714,32 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
state === KEYBOARD_STATE.SHOWN
) {
isExtendedByKeyboard.value = true;
animateToPoint(topInset);
animateToPoint(
topInset,
0,
keyboardAnimationDuration.value,
KEYBOARD_EASING_MAPPER[keyboardAnimationEasing.value]
);
return;
}
/**
* handle interactive behavior
*/
if (
keyboardBehavior === KEYBOARD_BEHAVIOR.interactive &&
state === KEYBOARD_STATE.SHOWN
) {
isExtendedByKeyboard.value = true;
const newSnapPoint = snapPoints[snapPoints.length - 1];
animateToPoint(newSnapPoint - keyboardHeight.value);
animateToPoint(
Math.max(topInset, newSnapPoint - keyboardHeight.value),
0,
keyboardAnimationDuration.value,
KEYBOARD_EASING_MAPPER[keyboardAnimationEasing.value]
);
}
},
[snapPoints, keyboardBehavior, topInset, animateToPoint]
);
/**
* set scrollable deceleration rate based on sheet
* position.
*/
useAnimatedReaction(
() => scrollableState.value,
(_scrollableState, _prevScrollableState) => {
if (_prevScrollableState === _scrollableState) {
return;
}
const newDecelerationRate =
_scrollableState === SCROLLABLE_STATE.UNLOCKED
? DECELERATION_RATE
: 0;
if (scrollableDecelerationRate.value !== newDecelerationRate) {
scrollableDecelerationRate.value = newDecelerationRate;
}
},
[snapPoints.length]
}
);
/**
@@ -790,14 +800,14 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
//#endregion
// render
console.log(
'BottomSheet',
'render',
snapPoints,
safeContainerHeight,
safeHandleHeight,
sheetHeight
);
// console.log(
// 'BottomSheet',
// 'render',
// snapPoints,
// safeContainerHeight,
// safeHandleHeight,
// sheetHeight
// );
return (
<BottomSheetProvider value={externalContextVariables}>
<BottomSheetBackdropContainer

View File

@@ -5,7 +5,6 @@ import { PanGestureHandler } from 'react-native-gesture-handler';
import { useBottomSheetInternal } from '../../hooks';
import type { BottomSheetDraggableViewProps } from './types';
import { styles } from './styles';
import { StyleSheet } from 'react-native';
const BottomSheetDraggableViewComponent = ({
nativeGestureRef,

View File

@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useCallback, useEffect } from 'react';
import {
Keyboard,
KeyboardEvent,
@@ -6,7 +6,11 @@ import {
KeyboardEventName,
Platform,
} from 'react-native';
import { runOnUI, useSharedValue } from 'react-native-reanimated';
import {
runOnUI,
useSharedValue,
useWorkletCallback,
} from 'react-native-reanimated';
import { KEYBOARD_STATE } from '../constants';
const KEYBOARD_EVENT_MAPPER = {
@@ -24,6 +28,7 @@ const KEYBOARD_EVENT_MAPPER = {
export const useKeyboard = () => {
//#region variables
const shouldHandleKeyboardEvents = useSharedValue(false);
const keyboardState = useSharedValue<KEYBOARD_STATE>(
KEYBOARD_STATE.UNDETERMINED
);
@@ -34,54 +39,79 @@ export const useKeyboard = () => {
const keyboardAnimationDuration = useSharedValue(0);
//#endregion
//#region worklets
const handleKeyboardEvent = useWorkletCallback(
(state, height, duration, easing) => {
if (state === KEYBOARD_STATE.SHOWN && !shouldHandleKeyboardEvents.value) {
return;
}
keyboardState.value = state;
keyboardHeight.value =
state === KEYBOARD_STATE.SHOWN
? height
: height === 0
? keyboardHeight.value
: height;
keyboardAnimationDuration.value = duration;
keyboardAnimationEasing.value = easing;
}
);
//#endregion
//#region callbacks
const handleOnKeyboardShow = useCallback(
(event: KeyboardEvent) => {
runOnUI(handleKeyboardEvent)(
KEYBOARD_STATE.SHOWN,
event.endCoordinates.height,
event.duration,
event.easing
);
},
[handleKeyboardEvent]
);
const handleOnKeyboardHide = useCallback(
(event: KeyboardEvent) => {
runOnUI(handleKeyboardEvent)(
KEYBOARD_STATE.HIDDEN,
event.endCoordinates.height,
event.duration,
event.easing
);
},
[handleKeyboardEvent]
);
//#endregion
//#region effects
useEffect(() => {
const handleKeyboardShow = (event: KeyboardEvent) => {
runOnUI((height, duration, easing) => {
keyboardState.value = KEYBOARD_STATE.SHOWN;
keyboardHeight.value = height;
keyboardAnimationDuration.value = duration;
keyboardAnimationEasing.value = easing;
})(event.endCoordinates.height, event.duration, event.easing);
};
Keyboard.addListener(
KEYBOARD_EVENT_MAPPER.KEYBOARD_SHOW,
handleKeyboardShow
handleOnKeyboardShow
);
return () => {
Keyboard.removeListener(
KEYBOARD_EVENT_MAPPER.KEYBOARD_SHOW,
handleKeyboardShow
handleOnKeyboardShow
);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [handleOnKeyboardShow]);
useEffect(() => {
const handleKeyboardHide = (event: KeyboardEvent) => {
runOnUI((height, duration, easing) => {
keyboardState.value = KEYBOARD_STATE.HIDDEN;
// prevent zeroing the height
keyboardHeight.value = height === 0 ? keyboardHeight.value : height;
keyboardAnimationDuration.value = duration;
keyboardAnimationEasing.value = easing;
})(event.endCoordinates.height, event.duration, event.easing);
};
Keyboard.addListener(
KEYBOARD_EVENT_MAPPER.KEYBOARD_HIDE,
handleKeyboardHide
handleOnKeyboardHide
);
return () => {
Keyboard.removeListener(
KEYBOARD_EVENT_MAPPER.KEYBOARD_HIDE,
handleKeyboardHide
handleOnKeyboardHide
);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [handleOnKeyboardHide]);
//#endregion
return {
@@ -89,5 +119,6 @@ export const useKeyboard = () => {
height: keyboardHeight,
animationDuration: keyboardAnimationDuration,
animationEasing: keyboardAnimationEasing,
shouldHandleKeyboardEvents,
};
};