Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PageView resize from zero-size viewport should not lose state #65015

Merged
merged 4 commits into from Sep 10, 2021

Conversation

xu-baolin
Copy link
Member

@xu-baolin xu-baolin commented Sep 1, 2020

Description

PageView resize from zero-size viewport should not lose state, otherwise will cause TabBar and TabBarView mismatch, see #64718

In _PagePosition.applyViewportDimension, If the viewport has a zero-size, the page can not be got by getPageFromPixels, so we need to cache the page for use when resizing the viewport to non-zero next time.

Related Issues

I have filed a new issue to reproduce this bug.
Fixes #88956

The following issues behaviors can not reproduce because the windows platform change some behaviors.
Fixes #64718
Fixes #55262

Tests

I added the following tests:

See files.

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.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read Handling breaking changes.

@flutter-dashboard flutter-dashboard bot added the framework flutter/packages/flutter repository. See also f: labels. label Sep 1, 2020
return newPosition.maxScrollExtent + oldDelta;
// If resize from zero, recover position from cache, so don't try to
// maintain the relative overscroll.
if (oldPosition.minScrollExtent != 0.0 || oldPosition.maxScrollExtent != 0.0) {
Copy link
Member Author

@xu-baolin xu-baolin Sep 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hixie Hi, Please review here, in this case, the _PagePosition.applyViewportDimension will correct the pixels due to resizing from zero, (such as oldPosithon here is (pixels: 800.0, minScrollExtent : 0.0, maxScrollExtent: 0.0)) and it will cause RangeMaintainingScrollPhysics.adjustPositionForNewDimensions mistake maintain the relative overscroll.
In addition, if the #63146 reland, we can remove this check and it works well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try to land the old PR again to make this moot.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(but with && -> ||)

// Cache the page when resize the viewport to zero.
// For use when resize the viewport to non-zero next time.
_cachePage = (viewportDimension == 0.0) ? page : null;

if (newPixels != oldPixels) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe here need to use nearEqual, I am not sure.

final double newPixels = getPixelsFromPage(page);

// Cache the page when resize the viewport to zero.
// For use when resize the viewport to non-zero next time.
_cachePage = (viewportDimension == 0.0) ? page : null;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In another extreme case, assuming that the viewport is very small, only 1 pixel, I ignore the processing of this kind of scene.

@Hixie
Copy link
Contributor

Hixie commented Sep 2, 2020

This seems reasonable, though I get this niggling feeling that it really means our whole design here is wrong, and that we should be deriving the pixel position from the page and not the other way around.

Let's wait until the RangeMaintainingScrollPhysics fix relands before landing this though, just to keep things simple...

@Piinks Piinks added a: desktop Running on desktop a: state restoration RestorationManager and related APIs f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. labels Sep 2, 2020
@Hixie
Copy link
Contributor

Hixie commented Sep 2, 2020

#65135 is the new fix for RangeMaintainingScrollPhysics.

@xu-baolin
Copy link
Member Author

This seems reasonable, though I get this niggling feeling that it really means our whole design here is wrong, and that we should be deriving the pixel position from the page and not the other way around.

Let's wait until the RangeMaintainingScrollPhysics fix relands before landing this though, just to keep things simple...

So you suggest that we should record the page in real-time, as long as the pixels change, and deprecate getPageFromPixels, right?

@Hixie
Copy link
Contributor

Hixie commented Sep 8, 2020

I'm imagining a world where the "pixels" getter returns a value derived from the "page" field. But I don't know if the design even makes that possible. You definitely don't need to try to implement that if you don't want to. It might be somewhat involved.

@Hixie
Copy link
Contributor

Hixie commented Sep 8, 2020

BTW the RangeMaintainingScrollPhysics has landed again, hopefully it sticks this time...

@xu-baolin
Copy link
Member Author

I'm imagining a world where the "pixels" getter returns a value derived from the "page" field. But I don't know if the design even makes that possible. You definitely don't need to try to implement that if you don't want to. It might be somewhat involved.

How about open a new topic to discuss how to refactor it?I totally agree that this will be a bit complicated :)
The PR looks very strong this time!

@xu-baolin
Copy link
Member Author

@Hixie Hi,
Review requested by manually : )

@iskakaushik
Copy link
Contributor

cc: @iskakaushik for looking at pausing the animator on 0 size window update.

@xu-baolin
Copy link
Member Author

@dnfield Hi,
Would you like to take a look at this? Thanks :)

@dnfield
Copy link
Contributor

dnfield commented Oct 12, 2020

@iskakaushik - are you saying that if we paused the animator in this case (which it seems like we should), we'd avoid this bug?

I'm not clear on how the viewport metrics are getting updated on Windows in the minimize case. It seems like we should be resolving that before doing anything else with this bug. IOW, it seems to me that getting a zero sized viewport shouldn't be happening when you minimize the window - but the animator should be paused.

@iskakaushik
Copy link
Contributor

@dnfield Yup. I will try to take a look at this sometime this week. IMO app minimization should be treated as application resigning from being active, we should re-use the last drawn frame and show it when the app becomes active again. I need to look at what macOS / Windows provide for us to achieve this behavior. I think the fix will be in the engine and not require us to handle 0 size window metrics events.

@dnfield
Copy link
Contributor

dnfield commented Oct 12, 2020

When we get the WM_SIZE message we should be checking whether the wparam is SIZE_MINIMIZED https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-size?redirectedfrom=MSDN for Windows

@xu-baolin
Copy link
Member Author

Actually, this is not a platform-related patch, setting the size to 0 will also trigger this bug in all the platforms.

@xu-baolin xu-baolin removed the a: desktop Running on desktop label Jan 6, 2021
@Piinks
Copy link
Contributor

Piinks commented Aug 17, 2021

@xu-baolin, can you update this PR if you would like to proceed with the change? I'd be happy to take a look if you would still like to land it. Thank you!

@xu-baolin
Copy link
Member Author

@xu-baolin, can you update this PR if you would like to proceed with the change? I'd be happy to take a look if you would still like to land it. Thank you!

OK

@xu-baolin
Copy link
Member Author

@xu-baolin, can you update this PR if you would like to proceed with the change? I'd be happy to take a look if you would still like to land it. Thank you!

Hi, I have updated this and it is ready for review now. Thanks!

Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good change. It is not addressing a platform specific bug as mentioned above, and it is very easy to reproduce this bug just by resizing the window on Mac to be very small. Thank you for another contribution @xu-baolin, and for updating it after so much time. :)

Comment on lines 450 to 451
// Cache the page when resize the viewport to zero.
// For use when resizing the viewport to non-zero next time.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Cache the page when resize the viewport to zero.
// For use when resizing the viewport to non-zero next time.
// If the viewportDimension is zero, cache the page
// in case the viewport is resized to be non-zero.

@@ -325,6 +325,10 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri

final int initialPage;
double _pageToUseOnStartup;
// When the viewport has a zero-size, the `page` can not
// be got by `getPageFromPixels`, so we need to cache the page
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// be got by `getPageFromPixels`, so we need to cache the page
// be retrieved by `getPageFromPixels`, so we need to cache the page

@@ -370,7 +384,8 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
double get _initialPageOffset => math.max(0, viewportDimension * (viewportFraction - 1) / 2);

double getPageFromPixels(double pixels, double viewportDimension) {
final double actual = math.max(0.0, pixels - _initialPageOffset) / math.max(1.0, viewportDimension * viewportFraction);
assert(viewportDimension > 0.0);
final double actual = math.max(0.0, pixels - _initialPageOffset) / (viewportDimension * viewportFraction);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

math.max(1.0, viewportDimension * viewportFraction) -> (viewportDimension * viewportFraction)

This fixes the issue when the viewport is less than 1.0 although it is not common.

@xu-baolin
Copy link
Member Author

xu-baolin commented Aug 31, 2021

@Piinks hi, I have added more changes to make sure that all work well when the viewport's size is zero.

Now change the page through the controller or TabBar will not lose state when the viewport size is zero.

@xu-baolin xu-baolin requested a review from Piinks August 31, 2021 11:33
Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates @xu-baolin! LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: state restoration RestorationManager and related APIs f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
7 participants