Repository navigation
fix(core): nested tab frames stay loaded and never outrank the selected tab - #11446
Merged
Merged
Conversation
…ed tab Re-assigning TabView.items with an array holding the same items removed and re-added every item, which unloaded and tore down the selected item's view. On iOS the re-added item's frame never loaded again (canBeLoaded is false until its controller exists), so navigation queued forever; on Android the frame's native view was recreated detached from its tab fragment. Items kept across the change now stay attached. Android preloads the neighbouring tabs, so their frames load and navigate while hidden; navigate() pushed them above the selected tab's frame, making Frame.topmost() (and the hardware back button) act on an invisible tab. A frame hidden by an ancestor is now kept at the bottom of the frame stack until its tab is selected. Fixes #11444
|
View your CI Pipeline Execution ↗ for commit 13e4800
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗ ☁️ Nx Cloud last updated this comment at |
commit: |
NathanWalker
added a commit
to nativescript-community/octane
that referenced
this pull request
Sep 23, 2026
The driver could not place a <tabviewitem> under a <tabview>, nor a view under an item, so tabbed apps had to build their TabView imperatively. A tab view's items now mirror its node's children: an item is listed once it holds a view, because core rejects a view-less item and a child attaches after its parent. Items are assigned once per batch, after every child has attached. Core tears down the items it keeps whenever the array changes (fixed in NativeScript 9.1.3, NativeScript/NativeScript#11446), so a mount must reach it as a single assignment to keep the selected tab loaded on earlier releases.
NathanWalker
added a commit
to nativescript-community/octane
that referenced
this pull request
Sep 23, 2026
The driver could not place a <tabviewitem> under a <tabview>, nor a view under an item, so tabbed apps had to build their TabView imperatively. A tab view's items now mirror its node's children: an item is listed once it holds a view, because core rejects a view-less item and a child attaches after its parent. Items are assigned once per batch, after every child has attached. Core tears down the items it keeps whenever the array changes (fixed in NativeScript 9.1.3, NativeScript/NativeScript#11446), so a mount must reach it as a single assignment to keep the selected tab loaded on earlier releases.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
PR Checklist
What is the current behavior?
A
Framehosted asTabViewItem.view(per-tab navigation stacks) can lose its navigation bookkeeping through two separate mechanisms, both reproduced deterministically inapps/toolbox(newnested-tab-framepages) on the iPhone simulator and a Pixel 6a API 35 emulator:TabView.itemsre-assigned with an array holding the same items (what a reactive renderer does on every update).onItemsChangedremoved and re-added every item, which unloaded and tore down the selected item's view. On iOS the re-added item'sFramewas never loaded again, becauseTabViewItem.canBeLoadedis only set after the load cascade has already run, soframe.isLoadedstayedfalsewhile the tab was on screen and everynavigate()sat in the queue until an app calledframe.callLoaded(). On Android the frame's native view was recreated detached from its tab fragment. On both platforms the selected tab went blank.androidOffscreenTabLimitdefaults to 1), so their frames load and navigate while hidden, andnavigate()pushed them to the top of the frame stack. Right after startupFrame.topmost()returned the off-screenDemosframe instead of the selectedHomeframe, and after selecting a tab it returned that tab's hidden neighbour.Frame.topmost().navigate()pushed a page into the invisible tab, and the hardware back button (Frame.goBack(Frame.topmost(window))) would have acted on it too.What is the new behavior?
TabViewBase.onItemsChangedkeeps items present in both arrays attached; only removed items are torn down and only new ones added (the Android override resets tab specs only for removed items). iOS additionally loads the selected item's view once its controller exists, so an item added to a loadedTabViewat the selected index is not left unloaded.ViewBasegains_isChildPresented(child);TabViewBaseoverrides it for the selected item.FrameBase._pushInFrameStack()only promotes a frame that every ancestor presents; a hidden frame is kept at the bottom of the stack (still found byFrame.getFrameById) until its tab is selected, when the existing_pushInFrameStackRecursive()call promotes it.Verified on device after the change: the reassignment keeps
isLoaded=trueand pushes keep working on both platforms; on AndroidFrame.topmost()is the selected tab's frame at startup and after every selection, with the preloaded neighbour parked below (stack=[Third, root, Home, Demos]after selectingDemos).Unit tests:
tab-view-common.spec.ts(retained/removed/added items, item moved between TabViews,_isChildPresented) and newframe stack presentationcases inframe-common.spec.ts(hidden frames stay off the top, remain findable by id, preloaded tab frame navigating does not outrank the selected tab, selection promotes it).Fixes #11444.