react-navigation / react-navigation

Routing and navigation for your React Native apps
https://reactnavigation.org
23.56k stars 5.03k forks source link

[Android] content goes behind header in @react-navigation/native-stack #10531

Open osliver opened 2 years ago

osliver commented 2 years ago

Current behavior

on android content appears behind header Screenshot_1650373585

import React from 'react';
import {View, Text} from 'react-native';

export const Content: React.FC = () => {
  return (
    <View style={{flex: 1, backgroundColor: 'lightblue'}}>
      <Text>Content</Text>
      <Text>Content</Text>
      <Text>Content</Text>
      <Text>Content</Text>
      <Text>Content</Text>
      <Text>Content</Text>
      <Text>Content</Text>
      <Text>Content</Text>
      <Text>Content</Text>
      <Text>Content</Text>
    </View>
  );
};

Navigation screen

     <MainStack.Screen
        name={Screens.Content}
        component={Content}
        options={{
          title: '',
          headerShown: true,
        }}
        />

Expected behavior

content starts below header

Reproduction

found issue during corporate project

Platform

Packages

Environment

package version
@react-navigation/native 6.0.10
@react-navigation/bottom-tabs 6.3.1
@react-navigation/drawer -
@react-navigation/material-bottom-tabs -
@react-navigation/material-top-tabs -
@react-navigation/stack 6.2.1
@react-navigation/native-stack 6.6.1
react-native-safe-area-context 4.2.4
react-native-screens 3.13.1
react-native-gesture-handler 2.2.0
react-native-reanimated 2.6.0
react-native-tab-view -
react-native-pager-view -
react-native 0.66.4
expo -
node 12.22.11
npm or yarn npm
github-actions[bot] commented 2 years ago

Hey! Thanks for opening the issue. The issue doesn't seem to contain a link to a repro (a snack.expo.dev link, a www.typescriptlang.org/play link or link to a GitHub repo under your username).

Can you provide a minimal repro which demonstrates the issue? A repro will help us debug the issue faster. Please try to keep the repro as small as possible and make sure that we can run it without additional setup.

github-actions[bot] commented 2 years ago

Couldn't find version numbers for the following packages in the issue:

Can you update the issue to include version numbers for those packages? The version numbers must match the format 1.2.3.

PatrickBokhove commented 2 years ago

I was encountering this issue too, and it got fixed for me when i downgraded @react-navigation/native-stack from 6.6.1 back to 6.2.2. Looking at their changelog, they did a lot of changes to the header since then.

channeladam commented 2 years ago

Same issue here - on Android, the content is hidden behind the header.

The only work-around I have found is to get the headerHeight from useHeaderHeight() and apply that as a top margin or padding.

I had trouble reproducing the issue, but have finally done so. For me, the issue occurs when an entering animation (e.g. fade in) is done within a component, using react-native-reanimated

Here is a snack - issue occurs when navigating to screen 1b.

https://snack.expo.dev/@adammcraven/adam-nav-issue

And react-native-reanimated also has an issue for this: https://github.com/software-mansion/react-native-reanimated/issues/2906

fleecmf commented 2 years ago

I was encountering this issue too

@react-navigation/native: 6.6.2 react-native: 0.68.0 react-native-reanimated : 2.8.0

wcastand commented 2 years ago

by adding enableLayoutAnimations(false); in my App.tsx the issue disappears. just in case it could help some people that don't use layout animations.

levi218 commented 2 years ago

For me, I added enableLayoutAnimations(true); and this patch to offset the content of the screen down a bit (so that it is not hidden by the header)

diff --git a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
index 774aafc..47ee72f 100644
--- a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
+++ b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
@@ -250,6 +250,7 @@ const SceneView = ({
                 presentation={presentation}
                 headerHeight={headerHeight}
               >
+                {headerShown !== false && isAndroid && <View style={{marginTop:headerHeight}}></View>}
                 {render()}
               </MaybeNestedStack>
             </HeaderHeightContext.Provider>
anwersolangi commented 2 years ago

Facing the same issue when using entering or exiting animation from the Reanimated, currently I have fixed using channeladam solution, but we need a permanent fix.

janicduplessis commented 2 years ago

I tracked down the issue to this code in react-native-reanimated

diff --git a/node_modules/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java b/node_modules/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java
index b0e33b0..dd754dd 100644
--- a/node_modules/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java
+++ b/node_modules/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/layoutReanimation/ReanimatedNativeHierarchyManager.java
@@ -272,28 +272,6 @@ public class ReanimatedNativeHierarchyManager extends NativeViewHierarchyManager
   public synchronized void updateLayout(
       int parentTag, int tag, int x, int y, int width, int height) {
     super.updateLayout(parentTag, tag, x, y, width, height);
-    if (isLayoutAnimationDisabled()) {
-      return;
-    }
-    try {
-      View viewToUpdate = this.resolveView(tag);
-      ViewManager viewManager = this.resolveViewManager(tag);
-      String viewManagerName = viewManager.getName();
-      View container = resolveView(parentTag);
-      if (container != null
-          && viewManagerName.equals("RNSScreen")
-          && this.mReaLayoutAnimator != null) {
-        this.mReaLayoutAnimator.applyLayoutUpdate(
-            viewToUpdate,
-            (int) container.getX(),
-            (int) container.getY(),
-            container.getWidth(),
-            container.getHeight());
-      }
-    } catch (IllegalViewOperationException e) {
-      // (IllegalViewOperationException) == (vm == null)
-      e.printStackTrace();
-    }
   }

   @Override

Note that reanimated doesn't build from source on Android so it might be harder to make that change.

alzalabany commented 2 years ago

alright, so to sum it up for a villager like me. how to resolve this?

diff --git a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
index 2a0730a..a8e30d3 100644
--- a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
+++ b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
@@ -291,6 +291,7 @@ const SceneView = ({
                 presentation={presentation}
                 headerHeight={headerHeight}
               >
+                {headerShown !== false && isAndroid && <View style={{marginTop:headerHeight}}></View>}
                 {render()}
               </MaybeNestedStack>
             </HeaderHeightContext.Provider>
efstathiosntonas commented 2 years ago

this is what happening, it's well explained on docs: https://reactnavigation.org/docs/native-stack-navigator#headertransparent

fixed it using this patch on 6.9.1:

@react-navigation+native-stack+6.9.1.patch

diff --git a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
index f605bd8..c5b4228 100644
--- a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
+++ b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
@@ -324,6 +324,7 @@ const SceneView = ({
                   headerTopInsetEnabled={headerTopInsetEnabled}
                 >
                   <HeaderBackContext.Provider value={headerBack}>
+                    {headerShown !== false && isAndroid && <View style={{marginTop:headerHeight}}></View>}
                     {render()}
                   </HeaderBackContext.Provider>
                 </MaybeNestedStack>
Maxth commented 2 years ago

this is what happening, it's well explained on docs: https://reactnavigation.org/docs/native-stack-navigator#headertransparent

fixed it using this patch on 6.9.1:

@react-navigation+native-stack+6.9.1.patch

diff --git a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
index f605bd8..c5b4228 100644
--- a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
+++ b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
@@ -324,6 +324,7 @@ const SceneView = ({
                   headerTopInsetEnabled={headerTopInsetEnabled}
                 >
                   <HeaderBackContext.Provider value={headerBack}>
+                    {headerShown !== false && isAndroid && <View style={{marginTop:headerHeight}}></View>}
                     {render()}
                   </HeaderBackContext.Provider>
                 </MaybeNestedStack>

I tried this solution but then I got a gap the same height like the header underneath each header. For me it worked putting the extra View further up the markup hierarchy:

diff --git a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
index f605bd8..7df21b7 100644
--- a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
+++ b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
@@ -280,6 +280,7 @@ const SceneView = ({
       // this prop is available since rn-screens 3.16
       freezeOnBlur={freezeOnBlur}
     >
+      {headerShown !== false && isAndroid && <View style={{marginTop: headerHeight}} />}
       <NavigationContext.Provider value={navigation}>
         <NavigationRouteContext.Provider value={route}>
           <HeaderShownContext.Provider

When using transition animations this causes flickering though - not an ideal workaround.

efstathiosntonas commented 2 years ago

@Maxth thank you for pointing out the flickering, I totally forgot that I had applied it and I was wondering why the screen was flickering when the keyboard was opened on Android and an absolute positioned animated TextInput was pulled up from the bottom of the screen. I've just applied my patch, fast tested on Android and then got back to iOS simulator to continue working and forgot about it.

I've applied your patch version and the issue persists as you mentioned. The only way for the flickering to go away is to use:

<IndexStack.Screen
          name="XXX"
          component={XXX}
          options={{
            headerTransparent: true
          }}
   />

demo video, no patch applied, at the beginning headerTransparent: true and at the end headerTransparent: false (default value):

https://user-images.githubusercontent.com/717975/197127491-b4f1c7a3-1420-4c18-915b-e5693085327e.mp4

ScreamZ commented 2 years ago

Still having content appearing behind the header, but only when i go to the screen then i go back then i go again (the second time and others, the header mask part of content)

Maxth commented 2 years ago

@efstathiosntonas Thanks, will try your solution to get rid of flickering.

bebe84 commented 1 year ago

I can confirm that indeed this is issue with react-native-reanimated lib, enableLayoutAnimations(false) does the job for now. I wonder why they are doing such nasty thing and only for Android.

Maxth commented 1 year ago

For anyone referencing this thread for a solution the issue was fixed by reanimated 2.14

efstathiosntonas commented 1 year ago

And here’s the PR that addresses this: https://github.com/software-mansion/react-native-reanimated/pull/3791

FedeRBeije commented 1 year ago

Hi, still having the same issue on android. "react-native-reanimated": "2.14.4", "@react-navigation/bottom-tabs": "^6.5.3", "@react-navigation/native": "^6.0.11", "@react-navigation/native-stack": "^6.7.0",

garrettg123 commented 1 year ago

I'm also seeing this. Changing headerTransparent: true to headerTransparent: false fixes it, but it doesn't look as nice.

Glaubenio commented 1 year ago

Still having the same issue here