diff --git a/src/components/bottomSheet/BottomSheet.tsx b/src/components/bottomSheet/BottomSheet.tsx index 62b7ec133..0cffa23ba 100644 --- a/src/components/bottomSheet/BottomSheet.tsx +++ b/src/components/bottomSheet/BottomSheet.tsx @@ -47,7 +47,7 @@ import { SHEET_STATE, SCROLLABLE_STATE, KEYBOARD_BLUR_BEHAVIOR, - KEYBOARD_DISMISS_THRESHOLD, + KEYBOARD_INPUT_MODE, SCROLLABLE_TYPE, WINDOW_HEIGHT, } from '../../constants'; @@ -65,6 +65,7 @@ import { DEFAULT_ANIMATE_ON_MOUNT, DEFAULT_KEYBOARD_BEHAVIOR, DEFAULT_KEYBOARD_BLUR_BEHAVIOR, + DEFAULT_KEYBOARD_INPUT_MODE, INITIAL_CONTAINER_HEIGHT, INITIAL_HANDLE_HEIGHT, INITIAL_POSITION, @@ -112,6 +113,7 @@ const BottomSheetComponent = forwardRef( // keyboard keyboardBehavior = DEFAULT_KEYBOARD_BEHAVIOR, keyboardBlurBehavior = DEFAULT_KEYBOARD_BLUR_BEHAVIOR, + android_keyboardInputMode = DEFAULT_KEYBOARD_INPUT_MODE, // layout handleHeight: _providedHandleHeight, @@ -282,19 +284,27 @@ const BottomSheetComponent = forwardRef( /** * Returns keyboard height that in the root container. */ - const getKeyboardHeightInContainer = useWorkletCallback( - () => - $modal - ? Math.abs( - animatedKeyboardHeight.value - - Math.abs(bottomInset - animatedContainerOffset.value.bottom) - ) - : Math.abs( - animatedKeyboardHeight.value - - animatedContainerOffset.value.bottom - ), - [$modal, bottomInset] - ); + const getKeyboardHeightInContainer = useWorkletCallback(() => { + /** + * if android software input mode is not `adjustPan`, than keyboard + * height will be 0 all the time. + */ + if ( + Platform.OS === 'android' && + android_keyboardInputMode === KEYBOARD_INPUT_MODE.adjustResize + ) { + return 0; + } + + return $modal + ? Math.abs( + animatedKeyboardHeight.value - + Math.abs(bottomInset - animatedContainerOffset.value.bottom) + ) + : Math.abs( + animatedKeyboardHeight.value - animatedContainerOffset.value.bottom + ); + }, [$modal, bottomInset]); //#endregion //#region state/dynamic variables @@ -568,11 +578,26 @@ const BottomSheetComponent = forwardRef( }, [_providedOnAnimate, animatedSnapPoints, animatedCurrentIndex] ); - const animateToPositionCompleted = useWorkletCallback(() => { - animatedAnimationState.value = ANIMATION_STATE.STOPPED; - animatedNextPosition.value = Number.NEGATIVE_INFINITY; - animatedNextPositionIndex.value = Number.NEGATIVE_INFINITY; - }); + const animateToPositionCompleted = useWorkletCallback( + function animateToPositionCompleted(isFinished: boolean) { + if (!isFinished) { + return; + } + runOnJS(print)({ + component: BottomSheet.name, + method: animateToPositionCompleted.name, + params: { + animatedCurrentIndex: animatedCurrentIndex.value, + animatedNextPosition: animatedNextPosition.value, + animatedNextPositionIndex: animatedNextPositionIndex.value, + }, + }); + animatedAnimationState.value = ANIMATION_STATE.STOPPED; + animatedCurrentIndex.value = animatedNextPositionIndex.value; + animatedNextPosition.value = Number.NEGATIVE_INFINITY; + animatedNextPositionIndex.value = Number.NEGATIVE_INFINITY; + } + ); const animateToPosition = useWorkletCallback( function animateToPosition( position: number, @@ -1002,22 +1027,6 @@ const BottomSheetComponent = forwardRef( context.isScrollablePositionLocked = false; } - /** - * dismiss the keyboard when panning down, when: - * - keyboard is shown. - * - distance is more than threshold. - * - scrollable content is on the top. - * - - */ - if ( - animatedKeyboardState.value === KEYBOARD_STATE.SHOWN && - translationY > KEYBOARD_DISMISS_THRESHOLD && - scrollableContentOffsetY.value === 0 && - Platform.OS === 'android' - ) { - runOnJS(Keyboard.dismiss)(); - } - /** * over-drag implementation. */ @@ -1405,7 +1414,6 @@ const BottomSheetComponent = forwardRef( animatedNextPositionIndex.value = -1; } else { nextPosition = animatedSnapPoints.value[_providedIndex]; - animatedNextPositionIndex.value = _providedIndex; } /** @@ -1434,7 +1442,6 @@ const BottomSheetComponent = forwardRef( if (animateOnMount) { animateToPosition(nextPosition); } else { - animatedNextPosition.value = nextPosition; animatedPosition.value = nextPosition; } isAnimatedOnMount.value = true; @@ -1508,7 +1515,14 @@ const BottomSheetComponent = forwardRef( * if new keyboard state is hidden and blur behavior is none, then exit the method */ (_keyboardState === KEYBOARD_STATE.HIDDEN && - keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.none) + keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.none) || + /** + * if platform is android and the input mode is resize, then exit the method + */ + (Platform.OS === 'android' && + (keyboardBehavior === KEYBOARD_BEHAVIOR.interactive || + keyboardBehavior === KEYBOARD_BEHAVIOR.none) && + android_keyboardInputMode === KEYBOARD_INPUT_MODE.adjustResize) ) { return; } @@ -1528,7 +1542,12 @@ const BottomSheetComponent = forwardRef( const nextPosition = getNextPosition(); animateToPosition(nextPosition, 0, animationConfigs); }, - [keyboardBlurBehavior, getNextPosition] + [ + keyboardBehavior, + keyboardBlurBehavior, + android_keyboardInputMode, + getNextPosition, + ] ); /** diff --git a/src/components/bottomSheet/constants.ts b/src/components/bottomSheet/constants.ts index 49e0de68d..c0922a977 100644 --- a/src/components/bottomSheet/constants.ts +++ b/src/components/bottomSheet/constants.ts @@ -2,6 +2,7 @@ import Animated, { Easing } from 'react-native-reanimated'; import { KEYBOARD_BEHAVIOR, KEYBOARD_BLUR_BEHAVIOR, + KEYBOARD_INPUT_MODE, WINDOW_HEIGHT, } from '../../constants'; import { exp } from '../../utilities/easingExp'; @@ -25,8 +26,11 @@ const DEFAULT_ENABLE_HANDLE_PANNING_GESTURE = true; const DEFAULT_ENABLE_OVER_DRAG = true; const DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE = false; const DEFAULT_ANIMATE_ON_MOUNT = false; + +// keyboard const DEFAULT_KEYBOARD_BEHAVIOR = KEYBOARD_BEHAVIOR.none; const DEFAULT_KEYBOARD_BLUR_BEHAVIOR = KEYBOARD_BLUR_BEHAVIOR.none; +const DEFAULT_KEYBOARD_INPUT_MODE = KEYBOARD_INPUT_MODE.adjustPan; // initial values const INITIAL_SNAP_POINT = -999; @@ -51,9 +55,11 @@ export { DEFAULT_ENABLE_OVER_DRAG, DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE, DEFAULT_ANIMATE_ON_MOUNT, + // keyboard DEFAULT_KEYBOARD_BEHAVIOR, DEFAULT_KEYBOARD_BLUR_BEHAVIOR, - // initial + DEFAULT_KEYBOARD_INPUT_MODE, + // layout INITIAL_POSITION, INITIAL_CONTAINER_HEIGHT, INITIAL_CONTAINER_OFFSET, diff --git a/src/components/bottomSheet/types.d.ts b/src/components/bottomSheet/types.d.ts index 3de2779ef..37cf2b5d0 100644 --- a/src/components/bottomSheet/types.d.ts +++ b/src/components/bottomSheet/types.d.ts @@ -8,6 +8,7 @@ import type { BottomSheetBackgroundProps } from '../bottomSheetBackground'; import type { KEYBOARD_BEHAVIOR, KEYBOARD_BLUR_BEHAVIOR, + KEYBOARD_INPUT_MODE, } from '../../constants'; export interface BottomSheetProps @@ -152,6 +153,14 @@ export interface BottomSheetProps * - `restore`: restore sheet position. */ keyboardBlurBehavior?: keyof typeof KEYBOARD_BLUR_BEHAVIOR; + /** + * Defines keyboard input mode for Android only. + * @link {https://developer.android.com/guide/topics/manifest/activity-element#wsoft} + * @type `adjustPan` | `adjustResize` + * @default `adjustPan` + */ + android_keyboardInputMode?: keyof typeof KEYBOARD_INPUT_MODE; + //#endregion /** diff --git a/src/constants.ts b/src/constants.ts index 5fc14ec8e..b72c86974 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -72,6 +72,11 @@ const KEYBOARD_BLUR_BEHAVIOR = { restore: 'restore', } as const; +const KEYBOARD_INPUT_MODE = { + adjustPan: 'adjustPan', + adjustResize: 'adjustResize', +} as const; + const KEYBOARD_DISMISS_THRESHOLD = 12.5; export { @@ -88,5 +93,6 @@ export { MODAL_STACK_BEHAVIOR, KEYBOARD_BEHAVIOR, KEYBOARD_BLUR_BEHAVIOR, + KEYBOARD_INPUT_MODE, KEYBOARD_DISMISS_THRESHOLD, }; diff --git a/src/utilities/animate.ts b/src/utilities/animate.ts index 290b8f52a..69aba3d08 100644 --- a/src/utilities/animate.ts +++ b/src/utilities/animate.ts @@ -5,7 +5,7 @@ export const animate = ( point: number, configs: Animated.WithSpringConfig | Animated.WithTimingConfig, velocity: number = 0, - onComplete?: () => void + onComplete?: (isFinished: boolean) => void ) => { 'worklet';