Skip to content

[iOS 14] ActionBar not respecting safe area, shown under the status bar #10067

Closed

Description

@fpaaske

Issue Description

I have an app using nested page routing outlets, and the ActionBar on the first tab of the nested page router outlet will appear under the status bar. The other tabs works as expected.

This only happens on iOS 14.x.

It happened after moving from @nativescript-community/ui-material-bottom-navigation to @nativescript-community/ui-material-bottomnavigationbar. However, it also happens when I remove the usage of the ui-material-bottomnavigationbar as well, and just use a custom tab bar, so it's probably not really linked to that.

There's a similar issue reported here: nativescript-community/ui-material-components#308

I've tried to set padding-/marginTop to force it down, without luck.

This is how it (correctly) looks on iOS 12, 15 and 16.
image

image


Here's iOS 14 on iPhone 8
image

image

iPhone X
image

image

iPhone 12 Pro
image

image

Reproduction

This is from another, simpler app, but same issue.

app.component

<page-router-outlet></page-router-outlet>
const routes: Routes = [
  {
    path: "",
    redirectTo: "tabs/default",
    pathMatch: "full",
  },
  {
    path: "tabs",
    loadChildren: () =>
      import("./features/tabs/tabs.module").then((m) => m.TabsModule),
  },
];

tabs.component

<GridLayout rows="* auto">
  <GridLayout row="0" [hidden]="selectedTabIndex !== 0">
    <page-router-outlet name="charactersTab"></page-router-outlet>
  </GridLayout>
  <GridLayout row="0" [hidden]="selectedTabIndex !== 1">
    <page-router-outlet name="seriesTab"></page-router-outlet>
  </GridLayout>

  <BottomNavigationBar row="1" class="bottom-navigation-bar"
                       (tabSelected)="tabSelected($event)"
                       (tabReselected)="tabReselected($event)"
  >
    <BottomNavigationTab title="Characters">
    </BottomNavigationTab>
    <BottomNavigationTab title="Series">
    </BottomNavigationTab>
  </BottomNavigationBar>
</GridLayout>
const routes: Routes = [
  {
    path: "default",
    component: TabsComponent,
    children: [
      {
        path: "characters",
        outlet: "charactersTab",
        component: NSEmptyOutletComponent,
        loadChildren: () =>
          import("~/features/character-list/character-list.module").then(
            (m) => m.CharacterListModule
          ),
      },
      {
        path: "series",
        outlet: "seriesTab",
        component: NSEmptyOutletComponent,
        loadChildren: () =>
          import("~/features/series-list/series-list.module").then(
            (m) => m.SeriesListModule
          ),
      },
    ],
  },
];

characters-list

<ActionBar title="Characters"></ActionBar>
<GridLayout rows="auto, *">
...
</GridLayout>

series-list

<ActionBar title="Series"></ActionBar>
<GridLayout rows="auto, *">
...
</GridLayout>

iPhone X iOS 12, all good:
image

image

iPhone X iOS 14

First tab, characters, NOT OK
image

image

Second tab, series, OK
image

image

Relevant log output (if applicable)

No response

Environment

OS: macOS 12.6
CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Shell: /bin/zsh
node: 16.16.0
npm: 8.11.0
nativescript: 8.3.3

# android
java: 11.0.16
ndk: Not Found
apis: 23, 30, 31, 32
build_tools: 30.0.3, 31.0.0, 33.0.0
system_images: 
  - android-23 | Google APIs ARM EABI v7a
  - android-23 | Google APIs Intel x86 Atom
  - android-23 | Google APIs Intel x86 Atom_64
  - android-24 | Google APIs Intel x86 Atom
  - android-30 | Google APIs Intel x86 Atom
  - android-30 | Google APIs Intel x86 Atom_64
  - android-30 | Google Play Intel x86 Atom
  - android-31 | Google APIs Intel x86 Atom_64
  - android-31 | Google Play Intel x86 Atom_64

# ios
xcode: 14.0.1/14A400
cocoapods: 1.11.2
python: 2.7.18
python3: 3.9.13
ruby: 2.7.6
platforms: 
  - DriverKit 21.4
  - iOS 16.0
  - macOS 12.3
  - tvOS 16.0
  - watchOS 9.0

Dependencies

"dependencies": {
  "@angular/animations": "~14.1.0",
  "@angular/common": "~14.1.0",
  "@angular/compiler": "~14.1.0",
  "@angular/core": "~14.1.0",
  "@angular/forms": "~14.1.0",
  "@angular/platform-browser": "~14.1.0",
  "@angular/platform-browser-dynamic": "~14.1.0",
  "@angular/router": "~14.1.0",
  "@nativescript-community/ui-collectionview": "^4.0.0",
  "@nativescript-community/ui-material-bottomnavigationbar": "^7.0.0",
  "@nativescript-community/ui-material-bottom-navigation": "^7.0.0",
  "@nativescript-community/ui-material-tabs": "^7.0.0",
  "@nativescript/angular": "^14.2.5",
  "@nativescript/core": "~8.3.1",
  "@nativescript/theme": "~3.0.2",
  "crypto-js": "^4.1.1",
  "rxjs": "~7.5.0",
  "zone.js": "~0.11.5"
},
"devDependencies": {
  "@angular-devkit/build-angular": "~14.1.0",
  "@angular/compiler-cli": "~14.1.0",
  "@nativescript/android": "~8.3.1",
  "@nativescript/ios": "~8.3.3",
  "@nativescript/types": "~8.3.1",
  "@nativescript/webpack": "^5.0.8",
  "@ngtools/webpack": "~14.1.0",
  "prettier": "2.7.1",
  "typescript": "~4.7.4"
}

Please accept these terms

Activity

  1. CatchABus commented on Oct 27, 2022

    @CatchABus
    Contributor

    Does this exact same problem occur if you also use TabView component? If not, I think the problem is on the plugin side and you should report it on the plugin repo.

  2. fpaaske commented on Oct 27, 2022

    @fpaaske
    Author

    As I mentioned, this also happens if I replace the plugin with a custom tab, e.g. GridLayout with buttons for tabs.

  3. CatchABus commented on Oct 27, 2022

    @CatchABus
    Contributor

    As I mentioned, this also happens if I replace the plugin with a custom tab, e.g. GridLayout with buttons for tabs.

    I see.
    There is a chance this is a simulator problem. I never noticed this problem on device with iOS 14.

  4. fpaaske commented on Oct 27, 2022

    @fpaaske
    Author

    Unfortunately, no. I've tested this on real device with iOS 14, and the problem is the same as on the simulator.

    Oddly enough, switching from page-router-outlet to regular router-outlet seems to solve the problem. But I'm not sure about what other consequences I might face later on with them.

    I'll see if I can share a repository illustrating the problem.

  5. added a commit that references this issue on Oct 27, 2022
  6. fpaaske commented on Oct 27, 2022

    @fpaaske
    Author

    @CatchABus I've uploaded a repo for you to check. To reproduce the issue, replace the router-outlet in src/features/tabs/tabs.component.html with page-router-outlet, run on iOS 14.x, and navigate inside the first tab.

    Unfortunately, there's a little pre-work required to get it up and running, but I hope it's not too bad, and worth it in the end 😄

  7. boris01 commented on Oct 28, 2022

    @boris01

    Hi @fpaaske
    I think that this is because of the NSEmtpyOutletComponent.
    The page-router-outlet should be wrapped with GridLayout in the NSEmptyOutletComponent.
    When I updated your project with the changes below it worked.

    Add this one to your project and insert it to the declarations in the app.module:

    import { Component, ViewChild } from "@angular/core";
    import { PageRouterOutlet } from "@nativescript/angular";
    import { Page } from "@nativescript/core/ui/page";
    
    
    @Component({
      selector: 'wrapped-empty-outlet-component',
      template:`<GridLayout><page-router-outlet isEmptyOutlet='true'></page-router-outlet></GridLayout>`
    })
    export class WrappedEmptyOutletComponentComponent {
      @ViewChild(PageRouterOutlet, { read: PageRouterOutlet, static: false }) pageRouterOutlet: PageRouterOutlet;
        constructor(private page: Page) {
            console.log("[WrappedEmptyOutletComponent] constructor")
            if (this.page) {
                this.page.actionBarHidden = true;
    
                this.page.on("loaded", () => {
                    if (this.pageRouterOutlet && this.page.frame) {
                        this.pageRouterOutlet.setActionBarVisibility(this.page.frame.actionBarVisibility);
                    }
                });
            }
        }
    }
    

    And then change this:

    {
            path: "characters",
            outlet: "charactersTab",
            component: NSEmptyOutletComponent,
            loadChildren: () =>
              import("~/features/character-list/character-list.module").then(
                (m) => m.CharacterListModule
              ),
          },
          {
            path: "series",
            outlet: "seriesTab",
            component: NSEmptyOutletComponent,
            loadChildren: () =>
              import("~/features/series-list/series-list.module").then(
                (m) => m.SeriesListModule
              ),
          },
    

    to:

          {
            path: "characters",
            outlet: "charactersTab",
            //component: NSEmptyOutletComponent,
            component: WrappedEmptyOutletComponentComponent,
            loadChildren: () =>
              import("~/features/character-list/character-list.module").then(
                (m) => m.CharacterListModule
              ),
          },
          {
            path: "series",
            outlet: "seriesTab",
            //component: NSEmptyOutletComponent,
            component: WrappedEmptyOutletComponentComponent,
            loadChildren: () =>
              import("~/features/series-list/series-list.module").then(
                (m) => m.SeriesListModule
              ),
          },
    
  8. fpaaske commented on Oct 29, 2022

    @fpaaske
    Author

    Thanks, @boris01! This solves the issue, but I'm a bit surprised that this is necessary.
    This raises a few questions (not sure who can answer);

    • If this is required, why isn't this already in place in the NSEmptyOutletComponent?
      • Even more so when the page-router-outlet is already wrapped in GridLayout in the tabs.component.html
    • Why is it only necessary on iOS 14?
      • It works without wrapping on iOS 12, 13, 15 and 16, as well as all Android versions I've tested.
    • Where is this mentioned in the docs 😅
      • This is the closest I could find, but it doesn't mention this.

    Finally, what do I lose, in my case, with router-outlet vs page-router-outlet?

  9. boris01 commented on Oct 29, 2022

    @boris01

    @fpaaske for a question about router-outlet vs page-router-outlet you can look here:
    https://v7.docs.nativescript.org/angular/core-concepts/angular-navigation
    As for the other questions, I would like to receive the answers as well.
    I found this solution after reading this issue:
    NativeScript/nativescript-angular#2116

  10. added a commit that references this issue on Oct 29, 2022
  11. NathanWalker commented on Oct 23, 2026

    @NathanWalker
    Contributor

    Addressed by #10134 (reset additional safe-area insets when they're zero), and the wrapper workaround above also resolves it. iOS 14 is no longer a supported target. Please open a new issue with a repro if the ActionBar sits under the status bar on current iOS versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug-pending-triageReported bug, pending triage to confirm.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions