fix: keep TabView body state across rebuilds that construct fresh Tab widgets - #1352
Open
smileheart0708 wants to merge 1 commit into
Open
fix: keep TabView body state across rebuilds that construct fresh Tab widgets#1352smileheart0708 wants to merge 1 commit into
smileheart0708 wants to merge 1 commit into
Conversation
… widgets bdlukaa#1344 keyed the body PageView pages by tab identity (ValueKey<Tab>). Tab does not implement ==, so apps that construct their tabs in build() — the standard Flutter pattern — get brand-new page keys on every rebuild: the lazy viewport treats every old page as removed and tears down the visible body, losing scroll positions, text field state and focus on each parent rebuild. Prefer the caller-provided Tab.key as the page identity (compared by value), falling back to tab identity for keyless tabs. Apply the same keying to the tab strip so its elements survive rebuilds too. Reorders still relocate each body (and its state) to its tab's new index via findChildIndexCallback. Adds regression tests: a stateful body's counter survives rebuilds that construct fresh Tab widgets with stable keys, and still follows its tab across a reorder.
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.
Fixes #1349. Follow-up to #1344, which fixed the reorder desync but introduced a regression for the most common way of building tabs.
What this PR changes
#1344 keyed the body
PageViewpages by tab identity (ValueKey<Tab>(item)).Tabdoes not implement==, so apps that construct their tabs inbuild()— the standard Flutter pattern, e.g. oneTabper item derived from app state — get brand-new page keys on every rebuild. The lazy viewport then treats every old page as removed and tears down the visible body, losing scroll positions, text field state and focus on each parent rebuild (described in #1349).This PR keys each body page (and each strip entry, which had the same identity churn since before #1344) on the caller-provided
Tab.keywhen available, falling back to tab identity for keyless tabs:ValueKey<Object?>(tab.key ?? tab)compares caller keys by value, so rebuilds that construct freshTabwidgets with stable keys no longer tear the body down.findChildIndexCallbackresolves old page keys to their new index with the same rule, so a body (and its state) still relocates to its tab's new index on reorder — for keyed and keyless (cached-instance) tabs alike.No public API changes;
CHANGELOG.mdupdated under## [next].Tests
Two regression tests added, both verified to fail on current
masterand pass with this change:TabView keeps body state across rebuilds that construct fresh Tab widgets— a stateful body's counter survives a rebuild that constructs brand-newTabwidgets carrying the same keys.TabView keeps body glued to its tab across a reorder of fresh Tab widgets— the counter still follows its tab when the tabs are reordered and every rebuild constructs freshTabwidgets.The existing reorder regression test from #1344 (cached
Tabinstances, no caller keys) still passes unchanged. Full suite:flutter test— all tests pass.dart formatclean; no new analyzer findings in touched files.Pre-launch Checklist
CHANGELOG.mdwith my changes