GeezerVison is showing github.com — fix(ios): safe area layout when page view is offset in its superview by edusperoni · Pull Request #11517 · NativeScript/NativeScript
Conversation
PR Checklist
What is the current behavior?
When a page's controller view does not start at (0,0) in its superview, safe-area layout breaks on iOS. The common trigger is page.ios.edgesForExtendedLayout = UIRectEdge.Bottom with a visible navigation bar: UIKit places the controller view below the bar (y ≈ 152pt with a large title).
Two places mix the controller view's frame (superview coordinates) with values in the view's own coordinates:
Page.onLayout gets the native frame from View.layout() and lays out its content to bottom - insets.bottom / right - insets.right. The content ends up taller than the page by the frame offset.
IOSHelper.getAvailableSpaceFromParent returns fullscreen = viewControllerView.frame. expandBeyondSafeArea compares it with safeAreaLayoutGuide.layoutFrame and the in-window position, which are both relative to the controller view, so the bottom check (inWindow.bottom >= safeArea.bottom + fullscreen.top) never passes.
What you see:
- A view with
iosOverflowSafeArea = true at the bottom of the page stops at the safe-area bottom instead of reaching the screen edge (under the home indicator).
- A native
UIToolbar at the bottom shows a gap below it. UIKit only extends a bar's background into the bottom safe area when the bar touches its superview's safe-area bottom, and the page content is the wrong size and position for that.
- A page with
edgesForExtendedLayout = Bottom inside a TabView gets its content pushed down by the offset, so the bottom rows end up under the tab bar.
What is the new behavior?
Page.onLayout subtracts the origin: childRight = right - left - insets.right, childBottom = bottom - top - insets.bottom.
getAvailableSpaceFromParent uses viewControllerView.bounds, so fullscreen, safeArea and inWindow share one coordinate space.
When the frame origin is (0,0), which is the default edgesForExtendedLayout = All case, both changes do nothing.
Tests
- New
apps/automated test SAFEAREALAYOUT.test_overflow_reaches_bottom_when_page_view_is_offset: a page with a visible ActionBar and edgesForExtendedLayout = Bottom, holding a GridLayout with rows *, 44 and an iosOverflowSafeArea Label in the bottom row. It checks that the page view is offset, then asserts that the page, grid and label all reach the screen bottom. On the iOS 26.3 simulator (iPhone 17 Pro) it fails without this change (GridLayout.bottom - actual:2970; expected: 2622) and passes with it.
- Full
apps/automated iOS suite on the same simulator: 1828 OK, 0 failed.
- Manually tested in a separate repro app: a pushed page with a large-title navigation bar and a child view controller, a fullscreen modal, a TabView, and a plain page with default edges. Each was run with an overflow label and with a native
UIToolbar at the bottom. Layouts with default edges are unchanged.
Follow-ups (not in this PR)
expandBeyondSafeArea still adds fullscreenPosition.left / fullscreenPosition.top in the right/bottom checks. Both are now always 0 on the controller-view and scroll-view paths, so the terms could be dropped.
IOSHelper.layoutView lays out the owner with controller.view.frame when the controller has child view controllers. This has no effect today because View.layout() reads the native frame again, but bounds would be consistent with this change.
- A page with
edgesForExtendedLayout = Bottom inside a TabView now lays out correctly at the bottom, but still shows an empty band of roughly 60pt under the navigation bar. It comes from the page reporting a top safe-area inset, set by the additionalSafeAreaInsets logic in UILayoutViewController.viewDidLayoutSubviews. This was already the case before this change and needs separate investigation.
- Not tested yet: iPad/landscape (left/right insets), sheet-style modals.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Page.onLayout received the native frame in superview coordinates but laid
out its content as if it started at the origin, making the content taller
than the page by the frame offset. IOSHelper.getAvailableSpaceFromParent
compared the controller view's frame (superview coordinates) with safe
area and in-window positions in the controller view's own coordinates, so
iosOverflowSafeArea views never expanded to the bottom edge.
This shows up when the page view does not start at (0,0), e.g. with
edgesForExtendedLayout = UIRectEdge.Bottom under a visible navigation bar.
nx-cloud
Bot
commented
Oct 10, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
|
View your CI Pipeline Execution ↗ for commit 6cdad60
| Command |
Status |
Duration |
Result |
nx run-many -t build -p core,webpack5,vite |
✅ Succeeded |
20s |
View ↗ |
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗
☁️ Nx Cloud last updated this comment at 2026-10-10 20:10:35 UTC
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Open in StackBlitz
npm i https://pkg.pr.new/@nativescript/core@11517
npm i https://pkg.pr.new/@nativescript/vite@11517
npm i https://pkg.pr.new/@nativescript/webpack@11517
commit: 6cdad60
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Oct 22, 2026
modos189
added a commit
to IITC-CE/IITC-Prime
that referenced
this pull request
Oct 22, 2026
Backports NativeScript/NativeScript#11517: for a Page, nativeViewProtected is the
controller's view, which a transition animates by transform, so its frame reads as
an off-screen rect while the safe-area values beside it are in bounds space.
This branch has not been deployed
No deployments
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|