Make disposing a ScrollPosition with pixels=null legal#44617
Make disposing a ScrollPosition with pixels=null legal#44617goderbauer merged 3 commits intoflutter:masterfrom
Conversation
|
Unrelated to the PR, you will probably need to merge with master to pass the failing macos tests. I think there was some changes to the Cirrus macos images. |
1eee71d to
edf2cb8
Compare
|
Thanks for the heads-up. Merged with master. |
|
The rationale looks good to me. I think that we would probably have to remove the regression test for the workaround I added. That test relies on the fact that the The underlying issue that the tab that was warped over would still be built would still be a problem, but there are already issues to track that situation. |
|
Why do we have to remove the test? It should still pass even with this change? |
|
It’s more so that the test will never fail now, since it used to fail on that assert without my workaround. However, now that the assert is removed, the test no longer serves that purpose |
|
The test ensures that we never add that assert back, so it still has a purpose :) After syncing offline we decided to rename it to better reflect its purpose. |
There was a problem hiding this comment.
nit:
final OverlayEntry entry2 = OverlayEntry(
maintainState: true,
opaque: true,
builder: (BuildContext context) {
return const Text('number2');
},
);
c669cdb to
2ec01d6
Compare
2ec01d6 to
30370bf
Compare
Description
Certain subclass of ScrollPosition (namely _TabBarScrollPosition and _PagePosition) are initialized with initialPixels = null because the initial scroll offset cannot be determined when the ScrollPosition is first constructed. To determine the scroll offset for these subclasses, the viewport dimensions need to be known. Therefore, determining the initial pixels value is deferred until layout when applyViewportDimension is called.
This creates a problem when such a ScrollPosition is disposed without ever doing a layout run: Prior to this change, ScrollPosition.dispose used to assert(pixels != null), which would fire for the aforementioned ScrollPosition if their associated Viewport has never been layed out.
There's a common scenario for this situation: A (scrollable) TabBar or PageView is part of an OverlayEntry that's covered by another opaque OverlayEntry. The covered OverlayEntry is never layed out because its not visible on screen (it is considered to be offstage). When the covering OverlayEntry is removed, the other OverlayEntry is moved in the RenderTree from its offstage to the onstage position. Since the content of the moved OverlayEntry is associated with a global key the containing Scrollable is deactivated at the old position and re-activated at the new position in the RenderTree. This reactivation at a new position in the tree causes didUpdateDependencies to be called on the State of Scrollable, which calls ScrollableState._updatePosition [1]. This method builds a new ScrollPosition based on ScrollConfiguration and ScrollPhysics inherited from the new position in the RenderTree. The old ScrollPosition is disposed (which used to throw since it still has pixels set to null, see above).
This change makes it legal to dispose a ScrollPosition that has pixels still set to null.
Alternatives considered:
Side node: For the _PagePosition a work-around for this problem had been implemented in #31581. This change makes the work-around unnecessary and its therefore removed.
[1]
flutter/packages/flutter/lib/src/widgets/scrollable.dart
Lines 314 to 333 in 35de8d5
Related Issues
Fixes #44269.
Tests
I added the following tests:
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change
Does your PR require Flutter developers to manually update their apps to accommodate your change?