mirror of
https://github.com/zhigang1992/react-native-bottom-sheet.git
synced 2026-01-12 22:50:12 +08:00
refactor: updated keyboard handling
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user