Open schiller-manuel opened 3 years ago
thanks @schiller-manuel for submitting this bug , i will look into this
The below component will prevent the flicker on mount. It is by no means foolproof but works for a single snap point use case.
import React, { FunctionComponent } from 'react';
import { BottomSheetBackdrop, BottomSheetBackdropProps } from '@gorhom/bottom-sheet';
import { useAnimatedReaction, useSharedValue, withTiming } from 'react-native-reanimated';
import { OPEN_ANIMATION_DURATION } from './constants';
const AntiFlickerBottomSheetBackdrop: FunctionComponent<BottomSheetBackdropProps> = ({ animatedIndex, ...rest }) => {
const adjustedAnimatedIndex = useSharedValue(0);
const hasOpened = useSharedValue(false);
useAnimatedReaction(() => animatedIndex.value, (data, prev) => {
if (prev == null) {
adjustedAnimatedIndex.value = withTiming(1, { duration: OPEN_ANIMATION_DURATION }, (isFinished) => {
if (isFinished) hasOpened.value = true;
});
}
if (hasOpened.value) adjustedAnimatedIndex.value = data;
});
return <BottomSheetBackdrop animatedIndex={adjustedAnimatedIndex} {...rest} />;
};
export default AntiFlickerBottomSheetBackdrop;
Ensure you also use the below animation config on the bottom sheet itself to align the timing.
const animationConfigs = useBottomSheetTimingConfigs({
duration: OPEN_ANIMATION_DURATION,
});
FYI: still happening on v4
And is not only V3 related, that happens in V2 too. One of the possible workarounds is to extend BackdropComponent with a new prop that conditionally turns off interpolation of opacity, and pass this prop when increasing the content height. It is super-hacky but works
I just created a PR that fixes this for V2: https://github.com/gorhom/react-native-bottom-sheet/pull/562, but I believe that it is going to be easy to migrate it to Reanimated 2 if anyone is interested in doing that
this should be fixed on 4.0.0-alpha.24
, i will look into your PR for v2
@somebody32
Seems to still be broken for 4.4.5.
@gorhom any update on this ? And are there going to be a new versions ?
Slightly improved version of the @benjamin-sweney component. It didn't work from the start but when i changed <AntiFlickerBottomSheetBackdrop />
to the <AntiFlickerBottomSheetBackdrop disappearsOnIndex={-1} appearsOnIndex={0} />
and in my <BottomSheetModal index={0} />
it started to work properly.
if (!hasOpened.value && prev != null && prev > data) {
adjustedAnimatedIndex.value = data;
}
This few lines above fix the bug when the modal is not fully opened and you press on the Backdrop to close it.
AntiFlickerBottomSheetBackdrop.tsx
import React, {FunctionComponent} from 'react';
import {
BottomSheetBackdrop,
BottomSheetBackdropProps,
} from '@gorhom/bottom-sheet';
import {
Easing,
useAnimatedReaction,
useSharedValue,
withTiming,
} from 'react-native-reanimated';
import {MODAL_LOGIC} from '@/constants/modal';
interface AntiFlickerBottomSheetBackdropProps extends BottomSheetBackdropProps {
disappearsOnIndex: number;
appearsOnIndex: number;
}
const AntiFlickerBottomSheetBackdrop: FunctionComponent<
AntiFlickerBottomSheetBackdropProps
> = ({animatedIndex, ...rest}) => {
const {disappearsOnIndex, appearsOnIndex} = rest;
const adjustedAnimatedIndex = useSharedValue(disappearsOnIndex);
const hasOpened = useSharedValue(false);
useAnimatedReaction(
() => animatedIndex.value,
(data, prev) => {
if (!hasOpened.value && prev != null && prev > data) {
adjustedAnimatedIndex.value = data;
}
if (prev == null) {
adjustedAnimatedIndex.value = withTiming(
appearsOnIndex,
{
duration: MODAL_LOGIC.OPEN_ANIMATION_DURATION,
easing: Easing.out(Easing.exp),
},
isFinished => {
if (isFinished) hasOpened.value = true;
},
);
}
if (hasOpened.value) adjustedAnimatedIndex.value = data;
},
);
return (
<BottomSheetBackdrop animatedIndex={adjustedAnimatedIndex} {...rest} />
);
};
export default AntiFlickerBottomSheetBackdrop;
the BottomSheetBackdropl was Flickering when the content height change and unfortunately nothing from the above solutions worked for me so I created my AntiFlickerBottomSheetBackdrop, may it help someone facing the same problem I faced
import {
BottomSheetBackdrop,
BottomSheetBackdropProps,
} from '@gorhom/bottom-sheet';
import React, { ComponentProps } from 'react';
import { useAnimatedReaction, useSharedValue } from 'react-native-reanimated';
export const AntiFlickerBottomSheetBackdrop = (
props: BottomSheetBackdropProps & ComponentProps<typeof BottomSheetBackdrop>,
) => {
const adjustedAnimatedIndex = useSharedValue(0);
// when it opening it start from -1 to 0
// when it closing it start from 0 to -1
// 0: is open -1: is close
// when the error happen it jump directly from 0 to -1
// when the problem end it jump back from -1 to 0
useAnimatedReaction(
() => props.animatedIndex.value,
(prepared, pre) => {
if (pre === null) {
// initial state
adjustedAnimatedIndex.value = prepared;
return;
}
const jumpForward = prepared - pre === 1;
const jumpBackward = pre - prepared === 1;
if (pre !== prepared && !jumpBackward && !jumpForward) {
adjustedAnimatedIndex.value = prepared;
}
},
);
return (
<BottomSheetBackdrop {...props} animatedIndex={adjustedAnimatedIndex} />
);
};
// usage
const renderBackdrop: React.FC<BottomSheetBackdropProps> = useCallback(
(p) => (
<AntiFlickerBottomSheetBackdrop
{...p}
pressBehavior={pressBehavior}
disappearsOnIndex={-1}
appearsOnIndex={0}
/>
),
[pressBehavior],
);
<BottomSheetModal
keyboardBehavior="interactive"
keyboardBlurBehavior="restore"
android_keyboardInputMode="adjustResize"
enableDynamicSizing
enablePanDownToClose
animateOnMount
backdropComponent={renderBackdrop}
/>
@mhsfh having tried your fix, there appears to be an initial flicker of the backdrop for me occasionally on presenting. I haven't been able to figure out a fix for that.
@gorhom have you had a chance to look at this again?
+1 - I'm hitting this too.
I don't understand why they don't make things that are simple and that everyone needs instead of making things so complicated that even a lot of people can't use all of the things that they have created.
https://user-images.githubusercontent.com/6340397/117680607-9ca02200-b1b1-11eb-851b-f30ab92622b6.mp4
Bug
I added a backdrop to the "Dynamic Snap Point" example and experienced flickering of the backdrop when:
Please see the attached screen recording.
The flickering is caused by the
opacity
of the backdrop which is derived fromanimatedIndex
:https://github.com/gorhom/react-native-bottom-sheet/blob/b5a6c659e2fd4a8ead5857d3f22c55c47f4fd82e/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx#L77-L81
When the bottom sheet is mounted,
contentHeight
is set to0
and thus theanimatedIndex
is calculated as1
. This initializes the backdrop with its target opacity.When
contentHeight
is updated inhandleOnLayout
and thus the snap points change,animatedIndex
drops to a value below1
and then reaches1
. This causes a change in the backdrop's opacity which looks like it's flickering.When
contentHeight
is increased, the same behavior is shown:When
contentHeight
is decreased,animatedIndex
stays at1
and no flickering occurs:Environment info
Steps To Reproduce
backdropComponent={BottomSheetBackdrop}
Describe what you expected to happen:
no flickering of backdrop
Ideally,
animatedIndex
would not change when the snap points are modified as done here. Maybe when the number of snap points stay the same,animatedIndex
should stay constant?Reproducible sample code
I modified the example app by adding the backdrop to the dynamic snap point example, please have a look: https://github.com/schiller-manuel/react-native-bottom-sheet/commit/86b628ec8c3a7f462346ecfadc461c85adcd0bbb