-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Control paint order / z-order of slivers, take 1 #163511
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
Conversation
In the PR, the first commit is the implementation that preserves existing behavior unchanged. The second commit removes the legacy behavior: So if we end up needing to keep the legacy behavior around, that first commit is the draft of how to do so. |
|
Results of some code archeology: The legacy behavior dates to when slivers were first introduced, in e82b18d / #7370 in 2017. There was a bit of discussion then about the choice of paint order: #7370 (comment) The reasoning there explains why it has the current behavior instead of painting the last sliver in front — which would be the behavior that matches A few weeks later in 2017, when shrink-wrapping viewports were implemented (5928d22 / #7790), those painted the last sliver in front, just like most other widgets. Naturally that caused a series of bug reports over the years, because it turned out some people wanted app bars in shrink-wrapped viewports, just like in other viewports. Those issues were fixed in 2021, in b65a235 / #73195, by just flipping the order around to paint the first sliver in front, which is nearly but not quite the same thing that non-shrink-wrapped viewports do. With this PR, all viewports by default paint their slivers in the same order that shrink-wrapped viewports have since 2021; and there's also an option to paint in the opposite order, as shrink-wrapped viewports did from 2017 to 2021, and as requested in #145592. |
|
Looks like Hopefully the same thing will be true of the Google internal tests. If not (and if it isn't easy to just fix them forward), I can remove the second commit from this PR to make a version that preserves the legacy default behavior exactly. |
Piinks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chunhtai could this have implications for semantic traversal? IIRC visitChildrenForSemantics always visits children in paint order.
| viewport, | ||
| } | ||
|
|
||
| /// Specifies an order in which to paint the slivers of a [ScrollView]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// Specifies an order in which to paint the slivers of a [ScrollView]. | |
| /// Specifies an order in which to paint the slivers of a [Viewport]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, done.
| if (firstChild == null) { | ||
| return children; | ||
| } | ||
| RenderSliver? child = center; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so nothing there was relying on that center-related quirk in CustomScrollView's paint order, just like nothing in the Flutter tree's own tests was doing so.
Can you say more about this? I wondered if this would impact cases with center.. I think scrollable_positioned_list relies heavily on the center property to drive their scroll to index logic. What quirk are you referring to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was referring to the quirk that the PR's first commit describes as SliverPaintOrder.centerTopFirstBottom, and documents here:
cb389bd#diff-46c7759851537103b628677eeaab4081a4abf52f213b92953703360ccb8a5534R66-R77
where the paint order is almost like the firstIsTop behavior, but gets more complicated when center is in use.
This PR doesn't change anything about the layout of the slivers or the handling of scroll positions — it's strictly about the paint order (and the semantics order which stays in sync with paint order, and the hit-test order which stays in sync as the reverse of paint order). So scroll-to-index logic shouldn't be affected.
|
Regarding to the semantics ordering, this change looks fine because the visiChildrenForSemantics is implemented based on the childrenInPaintOrder getter
|
Piinks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tentative LGTM to fire off the Google testing shard 😜
FYI for @Renzo-Olivares, we were chatting today about some strange semantics traversal behavior seen in single child scroll view, but not in the scroll view subclasses. Made me think of this since single child scroll view is implemented differently, and this will make it consistent across those classes.
|
Hmm, Google testing failed, alas. So I guess the next question is what those failures look like — whether it looks like they'd be trivial to just fix. It's probably not worth going through the breaking-change process for this: the existing behavior is a bit quirky, but I think for most applications the quirks will never come up. (They only come up if you (a) use If we decide the current version of this PR would be a breaking change, then I can revise it to a non-breaking-change version by basically reverting the second commit: |
|
Rebasing to trigger a fresh run of Google tests, I need to verify if the failures were unrelated. From what I saw it was not clear. |
|
Looks like the Google tests failed on this run too. I'll be curious to hear how the failures look. |
|
Unfortunately we had an infra issue here, I am re-triggering the tests because the results were deleted. 😮💨 |
Instead of the legacy behavior where the center sliver paints on top, just have the first sliver paint on top. This is quite a bit simpler to document and simpler to implement, and it removes variation between a shrink-wrapped and non-shrink-wrapped viewport. Moreover the new behavior is the same as the old whenever not using the `center` field; and it turns out there are no tests in the tree that notice the difference. So hopefully this won't even be a breaking change.
I took these out as a last-minute simplifying change... and I guess I must not have actually rerun the tests after doing so, oops. Turns out I put them there in the first place for a good reason.
This keeps things a bit cleaner for code that uses this feature.
|
I've set an alert to check back here at lunch 😉 |
|
Checking in, infra seems to be struggling with getting this tested. I pressed some buttons manually from the other side to try and get it going. Will check back at the end of the day. |
|
Hrmph. It appears that our infra tooling to copy and test PRs in Google is confounded on this one. I've seen this happen sometimes when it has been tested a number of times or grows in age. @gnprice can you push a fresh commit to see if it helps? If that does not help, I recommend one of two possible next steps - creating a new PR, -or- reverting the potentially breaking commit here, landing this and putting up that second commit in a separate change. |
|
OK, sent a fresh PR #164818, just rebasing this one. Hopefully that does it 🤞 |
|
Closing as superseded by #164818. |
Fixes #145592.
When slivers in a CustomScrollView overlap, this makes it possible to control which of the slivers will sit in front of the other one, meaning that it paints last and gets hit-tested first.
In this version there are two choices: the first sliver paints in front, or the last sliver paints in front. The first sliver in front is the default; it's the behavior needed for SliverAppBar, or other situations where the first sliver is some sort of header.
The existing behavior is actually quite a bit more complicated than that, with the "center" sliver painting in front, plus it varies depending on
shrinkWrap. As far as I can tell this behavior isn't documented anywhere. It's equivalent to first-sliver-in-front wheneverCustomScrollView.centerisn't being used; and in fact there don't seem to be any tests in the tree that notice the difference between the existing behavior and first-sliver-in-front.So although I actually have an implementation that preserves the more complex existing defaults, I'm hopeful we won't need it: if neither google3 nor customer tests are relying on that undocumented distinction either, then we can go ahead and simplify this behavior without a breaking change.
Pre-launch Checklist
///).