th3rdwave / react-native-safe-area-context

A flexible way to handle safe area insets in JS. Also works on Android and Web!
MIT License
2.09k stars 191 forks source link

SafeAreaView flickers with incorrect initial insets on Android #364

Open janicduplessis opened 1 year ago

janicduplessis commented 1 year ago

This seems to happen with translucent status bar, when it is initially rendered on app start.

jacobp100 commented 1 year ago

Can you provide a minimal repro?

janicduplessis commented 1 year ago

@jacobp100 I discovered this issue in the expensify app in the PR https://github.com/Expensify/App/pull/15778, will work on getting a minimal repro in the example app soon.

jacobp100 commented 1 year ago

Sorry I didn’t realise it was you 🤣 I’m not too familiar with the android side of things. Are the insets available when the view mounts?

janicduplessis commented 1 year ago

I think they are, but wrongly have a bottom value, which might be what causes the flicker. I noticed by logging initialWindowMetrics. Might be related to the flags the app window has initially.

jacobp100 commented 1 year ago

Oh interesting. I wonder if android does the same thing of reporting only the safe area that overlaps with the view itself

MichalKrakow commented 1 year ago

It flickers both android ios, on production build, development build, and inside expo. I use react navigation and only few of my views utilize SafeAreaView.

todorone commented 1 year ago

It may be connected with this issue - https://github.com/th3rdwave/react-native-safe-area-context/issues/186, which @jacobp100 by some reason closed without explanation on how it could be solved or workarounded.

jacobp100 commented 1 year ago

I closed it because there’s not enough information to reproduce it

zabojad commented 1 year ago

I'm seeing the same behavior with "react-native-safe-area-context": "4.2.5" on Android only...

jacobp100 commented 1 year ago

You need a full repo showing it because the config you put in your android manifest affects the behaviour of the library

zabojad commented 1 year ago

@jacobp100 Interesting! What exact parameters from the Android manifest file do affect the behavior of this lib?

EDIT: what easy changes could I try before following your suggestion of providing a reproducer?

jacobp100 commented 1 year ago

I don't work on Android anymore - so I don't remember

We have a ticket for this https://github.com/th3rdwave/react-native-safe-area-context/issues/349 - it would be really useful if someone is able to help out with this - because I won't be able to

HenrikZabel commented 11 months ago

@janicduplessis did you manage to fix it? If yes, could you share how you did it?

toviszsolt commented 4 months ago

Hello guys!

Update:

In the App.js I use the SafeAreaProvider:

<SafeAreaProvider>
    <HomeScreen onLayout={hideSplashScreen} />
    <StatusBar style="auto" translucent />
</SafeAreaProvider>

The HomeScreen wrapped with SafeAreaView:

<SafeAreaView onLayout={onLayout} style={[styles.flexFit, theme.container]}>
      <ScrollView
        contentContainerStyle={[styles.container]}
        showsVerticalScrollIndicator={false}
        keyboardDismissMode="interactive"
      >
      ...
     </ScrollView>
</SafeAreaView>

https://github.com/th3rdwave/react-native-safe-area-context/assets/18605518/e2df7891-3974-4c31-b575-2c246e3ed862

XantreDev commented 3 months ago

In my case problem was with incorrect initialWindowMetrics from the lib. First render. It get's some safe area insets

insets {"bottom": 24, "left": 0, "right": 0, "top": 38.095237731933594} frame {"height": 852.1904907226562, "width": 411.4285583496094, "x": 0, "y": 38.095237731933594}

Second rerender, after layout

layout {"height": 852.1904907226562, "width": 411.4285583496094, "x": 0, "y": 0}
 LOG  insets {"bottom": 0, "left": 0, "right": 0, "top": 0} frame {"height": 852.1904907226562, "width": 411.4285583496094, "x": 0, "y": 38.095237731933594}

SafeAreaProvider placed almost on the root.

 const Providers = ({ children }: PropsWithChildren) => (
  <SafeArea.Provider>
    <GestureHandlerRootView className="flex-1">
      <CacheLibraryProvider>
        <NavigationContainer
          theme={NAVIGATION_THEME}
          onStateChange={onNavigationStateChange}
          ref={setNavigationContainerRef}
        >
          <BottomSheetModalProvider>
            <ModalProvider>
              <NoInternetToast.Provider shouldShow={$$(!$isOnline.value)}>
                <LogoutProvider>{children}</LogoutProvider>
              </NoInternetToast.Provider>
            </ModalProvider>
          </BottomSheetModalProvider>
          <Toast />
        </NavigationContainer>
      </CacheLibraryProvider>
    </GestureHandlerRootView>
    <OrientationLocker orientation="PORTRAIT" />
  </SafeArea.Provider>
);

 const App = ({
  isHeadless,
}: {
  /**
   * ios specific props from firebase messaging https://rnfirebase.io/messaging/usage#background-application-state
   */
  isHeadless?: boolean;
}) => {
  useEffect(() => {
    Analytics.triggerEventByName('AppLaunched');
    //TODO: Rewrite the code to avoid using this hack
    void restartWatchIfStarted();

    SplashScreen.hide();
  }, []);

  useAntifraudService();

  if (isHeadless) {
    return null;
  }

  return (
    <Providers>
      <StatusBar backgroundColor={'#151515'} />
      <View className="absolute inset-0 bg-gray-700" />
      <NoInternetToast.Ui />

      <ConditionalRouting />
    </Providers>
  );
};

// eslint-disable-next-line import/no-default-export
export default withIAPContext(Sentry.wrap(App));
isaachinman commented 1 month ago

Anyone have any advice on how to solve this? Seeing this only on Android, Expo v50 / expo-router / react-navigation.

XantreDev commented 1 month ago

Our workaround is to set initial metrics for the lib as a fullscreen