Closed callaars closed 11 months ago
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.
Not stale.
I was experiencing this as well. Solved it by snapping the bottom sheet at 100%
Using adjustPan
as the window resize mode seems to help in a lot of cases but still has similar issues with multiple modals. Not to mention that moving a whole app to work with adjustPan
is just crazy talk.
I unfortunately cannot snap my bottom sheet to a 100%.
@larsmunkholm @callaars Is there a code example that I can see to solve this issue
@varshith5c This is a simplification, but essentially what I did:
export const Component = (props) => {
const [inputHasFocus, setInputHasFocus] = useState(false);
return (
<BottomSheet
snapPoints={[inputHasFocus ? "100%" : 200, "100%"]}
onClose={props.onClose}
>
<TextInput
onFocus={() => setInputHasFocus(true)}
onBlur={() => setInputHasFocus(false)}
/>
</BottomSheet>
);
};
Yes I put the reproducible code in the top issue description.
https://github.com/callaars/bottom-sheet-android-keyboard-issue
I can confirm this, when TextInput focused, onClose function on BottomSheet props will called
Hello, did anyone find a more stable solution to this issue? I started looking into it today and found a couple of interesting things.
The most important part is: I was able to get a definite value for how high the snap point must be before the whole sheet is closed. Turns out it is exactly the height of the expanded keyboard.
If the bottom sheet is even one pixel shorter than the keyboard, this condition momentarily evaluates to true and also this block of code is executed.
Unfortunately I am testing on a pretty complex project so there are a ton of moving parts, I plan on trying on a brand new project to hopefully find a suitable patch either for this library or reanimated itself.
With that said, I'd be curious to know if a more "official" solution is in the works.
I am using BottomSheetModal
and I could solve it just by adding a second snapPoint ['25%','100%‘] that is 100%. To make the modal behave more natural I added a snapToIndex(0) to a keyboardDidHide event:
useEffect(() => {
const hideSubscription = Keyboard.addListener('keyboardDidHide', () => {
bottomSheetModalRef.current?.snapToIndex(0);
});
return () => {
hideSubscription.remove();
};
}, []);
Here is the whole component:
import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import {BottomSheetModal, BottomSheetBackdrop} from '@gorhom/bottom-sheet';
import {Keyboard} from 'react-native';
import {BottomSheetDefaultBackdropProps} from '@gorhom/bottom-sheet/lib/typescript/components/bottomSheetBackdrop/types';
import {ModalsContext} from '../context/modals';
type Props = {
children: React.ReactNode;
name: string;
height: string;
modalProps?: any;
};
export const CustomModal: React.FC<Props> = ({
children,
name,
height,
modalProps,
}) => {
const {isOpenModal, setOpenModal} = React.useContext(ModalsContext);
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
useEffect(() => {
const hideSubscription = Keyboard.addListener('keyboardDidHide', () => {
bottomSheetModalRef.current?.snapToIndex(0);
});
return () => {
hideSubscription.remove();
};
}, []);
const open = useMemo(() => isOpenModal(name), [isOpenModal, name]);
useEffect(() => {
if (open) {
bottomSheetModalRef.current?.present();
} else {
bottomSheetModalRef.current?.dismiss();
}
}, [open]);
const snapPoints = useMemo(() => [height, '100%'], [height]);
const renderBackdrop = useCallback(
(
props: React.JSX.IntrinsicAttributes & BottomSheetDefaultBackdropProps,
) => (
<BottomSheetBackdrop
{...props}
disappearsOnIndex={-1}
appearsOnIndex={0}
/>
),
[],
);
return (
<BottomSheetModal
ref={bottomSheetModalRef}
index={0}
snapPoints={snapPoints}
onChange={index => {
if (index === -1) {
setOpenModal(name, false);
}
}}
backdropComponent={renderBackdrop}
{...modalProps}>
{children}
</BottomSheetModal>
);
};
It's a general component where the modal open states are managed through a context.
any update about this issue? I'm having this problem in production.
For me the way to resolve this was to go to adjustPan
system wide. Fortunately we only have very few problems converting to that but it isn't ideal.
Having exactly the same issue
Having the same issue as well! @TarikHuber workaround works as a temporary fix! 😄
I managed to reproduce this issue and sort of understand why this happens. Using a brand new React Native 0.71 project, which supports both Reanimated v2 and v3, I was able to determine that the issue only exists in v3, probably in withTiming
.
I have opened a PR that adds a 1ms delay to the resize animation, which solves the issue both on my test project and real project. If anyone knows more about how withTiming
or Reanimated in general work, we could create a PR to fix the root issue.
However, for now, the PR can be used as workaround.
Can confirm got the same problem with reanimated 3 and v5.
I swapped out android:windowSoftInputMode="adjustResize" to android:windowSoftInputMode="adjustPan" in the AndroidManifest.xml and now it seems to be working.
I've been spending a couple of days on this issue now, both trying to understand as much of the animation flow, and what triggers the different changes to all the internal values.
What seems to be the culprit of the issue is that deriving of the animatedIndex
value (here) is running earlier with Reanimated v3, than it does with v2.
This earlier execution gives animatedIndex
the value of -1
instead of 0
, and cause the onChange
and onClose
handles to be triggered.
The execution flow I have observed is as follows:
containerHeight
(container height reduces when keyboard appear). OnSnapPointsChange
reaction in 1., which performs an animation with configs.duration: 0
, which changes animatedPosition
from having the value of the old snapPoint position to the current snapPoint position and ending the animation right away, setting animatedAnimationState.value = ANIMATION_STATE.STOPPED;
animatedIndex
is derived here by interpolation based on the animaitedPosition
generated in 2. The derived value ends up beeing 0
.animatedIndex
and animatedPostition
. The flow ends here, as none of the conditionals in this block resolves to true.animatedIndex
here. The derived value ends up beeing -1
, since animatedPostition
has not been updated yet.animatedIndex
and animatedPostition
. The time it ends up triggering both the onChange
and the onClose
handles, as animatedIndex
is -1
and animatedCurrentIndex
is still 0
.I have not been able to understand why the flows are in different order with Reanimated v2 and v3. I have how ever understood why https://github.com/gorhom/react-native-bottom-sheet/pull/1497 by @emilioschepis works as a workaround.
By changing the duration of the animation in animateToPosition
from 0 to 1ms, the animation is stopped one frame later, leaving the animatedAnimationState.value = ANIMATION_STATE.RUNNING
when the onChange animatiedReaction is triggered, causing an early exit here
I can not say if that workaround is safe enough to be merged or not, as I do not have enough knowledge of the rest of the code. I suppose @gorhom is the best to decide, or finding out how to get the flow back to how it was with Reanimated v2 is best.
After some further investigation, I've come across this change in Reanimated, that is part of v3 and not v2.
My understanding of this change is that they change the abstraction around Shared Values
, and looking at the part of the code which I can understand, it looks like they changed from performing change detection in native code to js code. I suspect that change can have altered the timing of when useAnimatedReaction
and/or useDerivedValue
is triggered, in turn causing the different execution flows in this library.
I also came across a different issue (https://github.com/gorhom/react-native-bottom-sheet/issues/1416) which actually seems to be the same as the one we are experiencing here, just triggered by other actions than keyboard appearance, eg. window resizing on web and device rotation on mobile (not only on Android, but on iOS as well).
I've published a reproduction repo where you can easily experience the issue, either by focusing the BottomSheetTextInput
on Android, or by rotating the device while the sheet is open on iOS.
@gorhom could you take a look at this please?
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.
Not stale.
@callaars could you test this pr.
thanks @sondreluc for diving into the code base and detail the root cause.
@gorhom I see that the above fix was merged and pushed out to v5, but is there a plan to push it out to v4 as well?
@gorhom I'm still experiencing this on 5.0.0-alpha.9
. I'm on Expo v50 in case that matters, I have a bottom sheet modal with a simple form with 2 inputs (BottomSheetTextInput
), the entire form is not very tall but when I set the snapPoints
to anything lower than 100% it seems to sometimes work and sometimes the modal closes when either of the inputs is focused and the keyboard opens. Most of the times the bottom sheet closes.
For now as a hopefully temporary workaround I'm gonna leave it at 100% but I'm really hoping to figure out a fix.
Any ideas why it doesn't work for me after the fix?
Hello, we have the same issue and like @ybentz, the fix pushed in v5 doesn't seems to work for us ; We are also using Expo 50
I find that if you add 100% to your snapPoints and then set keyboardBehavior to either extend or fillParent, it fixes it. But thenyou get the stupid extra padding that blocks/shrinks the content inside the modal.
The only workaround is setting my smallest snapPoints to 51%.
Bug
On Android, when using Reanimated 3 (any 3.x version) the
BottomSheetModal
immediately closes itself when it is of a relatively small height (<200) and focuses aBottomSheetTextInput
. This does not happen when using a regularBottomSheet
.Incorrect:
Correct (when using a larger height):
Logs:
Incorrect:
Correct:
Environment info
Steps To Reproduce
BottomSheetModal
with a relative small height (<200) and aBottomSheetTextInput
.BottomSheetTextInput
Describe what you expected to happen:
When focussing the TextInput on a
BottomSheetModal
of any size I expect it not to close the bottom sheet.Reproducible sample code
https://github.com/callaars/bottom-sheet-android-keyboard-issue