capacitor icon indicating copy to clipboard operation
capacitor copied to clipboard

bug: Navigation bar overlaps app screen

Open rbalet opened this issue 1 year ago • 18 comments

Bug Report

Capacitor Version

Latest Dependencies:

  @capacitor/cli: 4.6.1
  @capacitor/core: 4.5.0
  @capacitor/android: 4.6.2
  @capacitor/ios: 4.4.0

Installed Dependencies:

  @capacitor/cli: 4.7.0
  @capacitor/core: 4.7.0
  @capacitor/android: 4.7.0
  @capacitor/ios: 4.7.0

[success] Android looking great! 👌
[error] Xcode is not installed

Platform(s)

Android 13

Current Behavior

Navigation bar overlaps app screen image

Expected Behavior

Not overlapping it image

Code Reproduction

The error only happen in production, here for a working example

Code Reproduction : https://github.com/rbalet/ionic-navigation-bar-overlaps

see the add - Code reproduction branch to see which code have been added

Other Technical Details

npm --version output: 9.6.2

node --version output: 18.15.0

Additional Context

  • It does not happen all the time
  • I didn't had this error before updating to Android 13, so seems to be related to this version
  • StatusBar.setOverlaysWebView({ overlay: false }) seems to fix this problem
  • The following also seems to help (Will update if I get any news)
  private _setStatusBar() {
    if (Capacitor.getPlatform() === 'android') {
      setTimeout(() => {
        StatusBar.setOverlaysWebView({ overlay: true })
        StatusBar.setBackgroundColor({ color: '#00000000' })
      }, 100)
    }
  }

rbalet avatar Mar 22 '23 05:03 rbalet

Can you give this a title?

markemer avatar Mar 22 '23 21:03 markemer

+1 facing the issue with Android 13 devices.

iamromec avatar Mar 27 '23 09:03 iamromec

any updates on this bug?

Bug starting from Android API level 33

cuz currently i wrote plugin android-safe-area

and in my app code

async checkInsets() {
    try {
      const { top, bottom } = await SafeArea.getInsets();
      document.documentElement.style.setProperty('--ion-safe-area-top', top + 'px');
      document.documentElement.style.setProperty('--ion-safe-area-bottom', bottom + 'px');
    } catch (e) {
      console.error(e);
    }
  }
.keyboard-is-open {
    height: calc(100% - var(--keyboard-offset, 250px) - var(--ion-safe-area-bottom, 22px));
}

Now it freaky working, but we need to be it fixed in core. Thanks in advance.

qliqdev avatar Apr 15 '23 07:04 qliqdev

I also have this issue on Android 13 but using cordova

MasterAzazel avatar Jun 15 '23 09:06 MasterAzazel

I also have this issue on Android 13 but using cordova

Same here

9t96 avatar Jun 21 '23 18:06 9t96

seems to be kind of a race condition too. i had an app bootstrapping and while initally mounting the first view, i set the OverlaysWebview to true. this dindt work reliably, when switching to do it in a setTimeou(... , 0) wrapper it started working as expected again. I did not investigate any further yet as this was a rather urgend hotfix.

de-robat avatar Jul 05 '23 12:07 de-robat

Please, do just upvote the main issue instead of writing "non helpful text" so that the ionic team can better see if this have to be prioritised

Thx a lot <3

rbalet avatar Jul 05 '23 12:07 rbalet

I've encountered the problem and solved the issue; My expected setup is

  1. statusBar transparent
  2. statusBar dark content (light mode)
  3. webView renders behind statusBar
  4. navBar transparent
  5. navBar dark content (light mode)
  6. webView renders behind navBar (we failed to achieve this and gave up in Capacitor 4)

What happened was

  1. on Capacitor 4, I couldn't get webView to render behind navBar, regardless of android version.
  2. After our team bumped up to Capacitor 5, on android 13 specifically, we faced an issue in which the setup code had no effect on plugin load time (current issue's problem). android 12 and behaved the same.
  3. When we changed the entire setup code's to execute 200ms(arbitrarily chosen) after webView load, the setup had full effect! (current issue's solution, thanks to @de-robat )
  4. Interestingly, the previous issue of not being able to get webView render behind navBar was solved in Capacitor 5 + android 13. The issue persists in android 12 & below, even with Capacitor 5.

Following snippet is my android setup function and is almost same with the ones in @capacitor/status-bar


    private void setStatusBarAndNavBar() {
        var activity = this.bridge.getActivity();
        Window window = activity.getWindow();
        View decorView = window.getDecorView();
        WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, decorView);

        // 1. statusBar content color dark (light mode)
        windowInsetsControllerCompat.setAppearanceLightStatusBars(true);
        // 2. navBar content color dark (light mode)
        windowInsetsControllerCompat.setAppearanceLightNavigationBars(true);
        // 3. statusBar background color transparent
        window.setStatusBarColor(Color.TRANSPARENT);
        // 4. navBar background color transparent
        window.setNavigationBarColor(Color.TRANSPARENT);

        // 5. set render behind statusBar / navBar
        // This had no effect on navBar on <android 12 and below + Capacitor 4>, but
        // webview successfully rendered behind on navBar on <android 13 + Capacitor 5>
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        int uiOptions = decorView.getSystemUiVisibility();
        uiOptions = uiOptions | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);
    }

jjang16 avatar Jul 06 '23 16:07 jjang16

I created a plugin for android fullscreen mode: https://github.com/digaus/community-capacitor-fullscreen

Just install and add this somewhere:

           Fullscreen.addListener('insetsChanged', (insets: { top: number, bottom: number, left: number, right: number }) => {
                const style = document.documentElement.style;
                style.setProperty('--ion-safe-area-top', `${insets.top}px`);
                style.setProperty('--ion-safe-area-bottom', `${insets.bottom}px`);
                style.setProperty('--ion-safe-area-left', `${insets.left}px`);
                style.setProperty('--ion-safe-area-right', `${insets.right}px`);
                window.dispatchEvent(new Event('resize'));
            }).catch(() => null);
            StatusBar.setOverlaysWebView({ overlay: true });

digaus avatar Aug 04 '23 09:08 digaus

I created a plugin for android fullscreen mode: https://github.com/digaus/community-capacitor-fullscreen

Just install and add this somewhere:

           Fullscreen.addListener('insetsChanged', (insets: { top: number, bottom: number, left: number, right: number }) => {
                const style = document.documentElement.style;
                style.setProperty('--ion-safe-area-top', `${insets.top}px`);
                style.setProperty('--ion-safe-area-bottom', `${insets.bottom}px`);
                style.setProperty('--ion-safe-area-left', `${insets.left}px`);
                style.setProperty('--ion-safe-area-right', `${insets.right}px`);
                window.dispatchEvent(new Event('resize'));
            }).catch(() => null);
            StatusBar.setOverlaysWebView({ overlay: true });

@digaus So it actually will make the app render behind the status and navigation bars and you also get safe-area-insets for android devices ? Do you also had issues that on android the safe area insets didn’t work ? Did you also resolved that in your plugin ?

ngmiduc avatar Aug 11 '23 18:08 ngmiduc

I created a plugin for android fullscreen mode: https://github.com/digaus/community-capacitor-fullscreen Just install and add this somewhere:

           Fullscreen.addListener('insetsChanged', (insets: { top: number, bottom: number, left: number, right: number }) => {
                const style = document.documentElement.style;
                style.setProperty('--ion-safe-area-top', `${insets.top}px`);
                style.setProperty('--ion-safe-area-bottom', `${insets.bottom}px`);
                style.setProperty('--ion-safe-area-left', `${insets.left}px`);
                style.setProperty('--ion-safe-area-right', `${insets.right}px`);
                window.dispatchEvent(new Event('resize'));
            }).catch(() => null);
            StatusBar.setOverlaysWebView({ overlay: true });

@digaus So it actually will make the app render behind the status and navigation bars and you also get safe-area-insets for android devices ? Do you also had issues that on android the safe area insets didn’t work ? Did you also resolved that in your plugin ?

Yes, that's what the 'insetsChanged' is for.

Also takes care of rotation and inset changes.

Furthermore I added functions to change the color of the Statusbar and Navigationbar Icons/Buttons

digaus avatar Aug 12 '23 11:08 digaus

I am having the exact same issue, for capacitor 4 it was great, i just updated to 5 and have this issue. When i put app to the background and then back in foreground it fixes itself.

jovicailievski avatar Aug 16 '23 12:08 jovicailievski

I actually also have that problem with capacitor 4. Whenever the app launches I have this problem. When a request for persmissions appears, or i put the app in the backround and then again in the foreground, the problem is fixed temporarely until i completely close the app.

highvibesonly avatar Aug 24 '23 11:08 highvibesonly

same :-( capacitator 5 and android 13 image

ponsoc avatar Nov 14 '23 19:11 ponsoc

Adding a small delay between hiding splash screen and modifying the status bar will resolve this issue.

await SplashScreen.hide();
await new Promise(resolve => setTimeout(resolve, 500))
await StatusBar.setStyle({ style: Style.Light });
await StatusBar.setBackgroundColor({ color: '#FFFFFFF' });

Full example here: https://gist.github.com/enesien/5e64d0f29235ece5ecefad025110caf7

enesien avatar Nov 14 '23 20:11 enesien

I also have this issue on Android 13 but using cordova

Have you found any solutions to the problem. I am using cordova android platform 12.0.1. I tried making the StatusBar.overlaysWebView(false) while the device is ready. then set a timeout and changed to StatusBar.overlaysWebView(true). But still doesn't solve the issue.

AdnanABF avatar Dec 01 '23 19:12 AdnanABF

  1. Delete this code block if you have it: getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
  2. Use this: if (this.platformService.isAndroid()) { StatusBar.setOverlaysWebView({overlay: true}) }

And u need write it in style.xml, it is mandatory here to assign a color to android:statusBarColor:

These steps work for me and solved this bug, now the status bar is transparent and works as it should.

It is photo: https://github.com/ionic-team/capacitor/assets/64776696/8eb3a7e3-19b5-426d-b275-270b7d247544

Succu8 avatar Dec 11 '23 03:12 Succu8

This is what I did to fix the issue

In onCreate in MainActivity.java

        // Set app to fullscreen and the top status bar to transparent so the webview can render underneath it
        // Taken from https://github.com/ionic-team/capacitor-plugins/blob/33bdae1d3e73ac0bc63894d1cf714c57915b0605/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBar.java#L61
        View rootView = findViewById(android.R.id.content);
        int uiOptions = rootView.getSystemUiVisibility();
        uiOptions = uiOptions | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
        rootView.setSystemUiVisibility(uiOptions);
        this.getWindow().setStatusBarColor(Color.TRANSPARENT);

        // Set margin so that the bottom system navigation bar doesn't clip into the webview in fullscreen mode
        // Taken from https://developer.android.com/develop/ui/views/layout/edge-to-edge#system-bars-insets
        ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, windowInsets) -> {
            Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
            ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
            mlp.bottomMargin = insets.bottom;
            v.setLayoutParams(mlp);
            return WindowInsetsCompat.CONSUMED;
        });

Then I removed the call to StatusBar.setOverlaysWebView in my frontend code. Now the navigation bar doesn't clip over the webview anymore.

sam-hu avatar Jul 09 '24 02:07 sam-hu