From 0927e03687662c733582c6419396bbb20a95027b Mon Sep 17 00:00:00 2001 From: Krzysztof Magiera Date: Wed, 27 Nov 2019 12:35:26 +0100 Subject: [PATCH] Fix navbar window fitting on Android. (#235) This change fixes the issue of handling transparent status bar. In such a case the navbar should became slightly bigger in order to fill the status bar space that now belongs to the window. In order for that to happen we use `setFitsSystemWindows` on main screen layout, on app bar layout and on toolbar (the toolbar is the view that gets bigger in the end). Note that this currently only work if we use Android's native mechanism for changingthe status bar behavior and not using `StatusBar` module from RN. It is because `StausBar` module actually strips top insets from the event that gets delivered to the views. For the time being you can try the following to change status bar: ``` getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); ``` Note that we are also disabling app bar's scroll behavior. We wasn't utilising this yet, and it cause some weird errors on hot reload because scrolling behavior actually sets `firsSystemWindows` flag on the screen view which ended up consuming insets before appbar would get them. --- .../com/swmansion/rnscreens/ScreenStack.java | 32 ++++++++++++++++++- .../rnscreens/ScreenStackFragment.java | 6 ++-- .../rnscreens/ScreenStackHeaderConfig.java | 1 + 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStack.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStack.java index 6e7221ab..52061574 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStack.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStack.java @@ -1,7 +1,11 @@ package com.swmansion.rnscreens; import android.content.Context; +import android.view.View; +import android.view.WindowInsets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; @@ -32,6 +36,15 @@ public class ScreenStack extends ScreenContainer { public ScreenStack(Context context) { super(context); + + ViewCompat.setOnApplyWindowInsetsListener(this, + new androidx.core.view.OnApplyWindowInsetsListener() { + @Override + public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { + setWindowInsets(insets); + return insets; + } + }); } public void dismiss(ScreenStackFragment screenFragment) { @@ -53,6 +66,24 @@ public class ScreenStack extends ScreenContainer { throw new IllegalStateException("Stack has no root screen set"); } + private void setWindowInsets(WindowInsetsCompat insets) { + // we allow each screen to handle insets separately as they are all attached to the same parent + // and take up full screen. Therefore we make a copy of each inset object before passing it down + // to views. + boolean consumed = false; + for (int i = mScreenFragments.size() - 1; i >= 0; i--) { + ScreenStackFragment screen = mScreenFragments.get(i); + if (!mDismissed.contains(screen) && screen.getView() != null) { + if (ViewCompat.dispatchApplyWindowInsets(screen.getView(), new WindowInsetsCompat(insets)).isConsumed()) { + consumed = true; + } + } + } + if (consumed) { + insets.consumeSystemWindowInsets(); + } + } + @Override protected ScreenStackFragment adapt(Screen screen) { return new ScreenStackFragment(screen); @@ -70,7 +101,6 @@ public class ScreenStack extends ScreenContainer { fm.removeOnBackStackChangedListener(mBackStackListener); fm.popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); } - } @Override diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java index c38906d6..5b3b138e 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java @@ -64,20 +64,22 @@ public class ScreenStackFragment extends ScreenFragment { @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { CoordinatorLayout view = new CoordinatorLayout(getContext()); + view.setFitsSystemWindows(true); CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); - params.setBehavior(new AppBarLayout.ScrollingViewBehavior()); mScreenView.setLayoutParams(params); view.addView(mScreenView); mAppBarLayout = new AppBarLayout(getContext()); + mAppBarLayout.setFitsSystemWindows(true); // By default AppBarLayout will have a background color set but since we cover the whole layout // with toolbar (that can be semi-transparent) the bar layout background color does not pay a // role. On top of that it breaks screens animations when alfa offscreen compositing is off // (which is the default) mAppBarLayout.setBackgroundColor(Color.TRANSPARENT); mAppBarLayout.setLayoutParams(new AppBarLayout.LayoutParams( - AppBarLayout.LayoutParams.MATCH_PARENT, AppBarLayout.LayoutParams.WRAP_CONTENT)); + AppBarLayout.LayoutParams.MATCH_PARENT, + AppBarLayout.LayoutParams.WRAP_CONTENT)); view.addView(mAppBarLayout); if (mToolbar != null) { diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java index c9789ba2..11453f49 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java @@ -47,6 +47,7 @@ public class ScreenStackHeaderConfig extends ViewGroup { setVisibility(View.GONE); mToolbar = new Toolbar(context); + mToolbar.setFitsSystemWindows(true); // set primary color as background by default TypedValue tv = new TypedValue();