-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Allow OverlayPortal.overlayChild to compute the paint transform from OverlayPortal.child to the target overlay
#163575
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
Such that nobody `implements` it. Currently it has private APIs used by the `RenderObject` class (e.g., the dirty lists). If someone were to implement a `PipelineOwner` outside of object.dart, they will get a runtime crash since they won't be able to provide those private APIs and RenderObjects actually expect those APIs to exist.
This allows `overlyChild` to inspect the layout of the regular child (for example, computing the size and the paint transform from the Overlay to the regular child in `overlayChild`'s performLayout method).
…ays-add-to-dirty-list
…ays-add-to-dirty-list
…ongCatIsLooong/flutter into OverlayPortal-always-add-to-dirty-list
|
In case it is useful to someone: It is already possible to have overlay widget that tracks the anchor and can adjust size / position depending on available space without the 1 frame delay. Here is it in action. You can see it in action by opening the overlay, making the window small and scrolling. In the example size is not adjusted but the constrains are calculated dynamically taking anchor location into action so it's possible. EDIT: Actually, the size in example is adjusted dynamically so the popover always fits the bounds. And here is the implementation. It relies on persistent frame callback to ensure the layout always up to date. but due to layout boundaries the overhead should be negligible. |
@knopp This is very interesting, thanks! Quick question after looking at the implementation: it looks like the implementation maintains its own persistent callback queue, which will be drained after I couldn't find a way to schedule those |
|
It calls The second reason why this works is that the (it's been a while since a wrote this so maybe I'm misremembering something, but this should be it). |
To check my own understanding: |
goderbauer
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.
Overall this looks reasonable to me.
| /// child undergoes layout. Otherwise, the child can change its layout | ||
| /// information without informing this render object. | ||
| /// | ||
| /// It is recommended to establish / update the paint transform of this render |
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 assume this means you want applyPaintTransform to return the correct answer after layout? Maybe link to that method from here so people have context on what the "paint transform" is?
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.
Maybe also have it link to getTransformTo for even more context.
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.
Rephrased the paragraph. Note to myself to change the backticks to square brackets in PR2 for the OverlayPortal.overlayChildLayoutBuilder reference.
| // Instead of laying out this subtree via treewalk, adding it to the dirty | ||
| // list. This ensures: | ||
| // | ||
| // 1. this node will be laid out by the PipelineOwner *after* the two |
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.
For my own understanding (and worthwhile to document here): the after is guaranteed because this RO has a higher depth than the theater and surrogate?
| } | ||
|
|
||
| @override | ||
| void layout(Constraints constraints, {bool parentUsesSize = false}) { |
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.
Is it okay that we completely ignore the parentUsesSize here? Maybe leave a comment on why? And should we also assert that it actually isn't set by the parent?
…ays-add-to-dirty-list
I think I was thinking about the following case: Flex(
children: [ A, B, CompositedTransformFollower_C, D]
)where the parent render box would still reserve space for the transform follow (C), and at the same time C's offset is determined by something else (its Target). I don't know if there are practical use cases |
This API allows the widget tree of an `OverlayPortal.overlayChild` to depend on various layout information (e.g. the incoming constraints, or the size of a RenderObject) from another child subtree of `Overlay` that does layout before the `overlayChild`. Most RenderObject subclasses can only access its child's or children's layout info, but not the layout info of its other descendants because of the "relayout boundary" optimization. Such locality makes the layout dependencies easier to reason about but it also makes it difficult to implement certain common UI patterns (see the examples in the description of the [previous PR](#163575)) The API is currently only available on `OverlayPortal` as it is the only Overlay API (AFAIK) that guarantees every render object in a "path" within the render tree has finished doing layout. TODO: polish the API docs and code comments TODO: more tests? TODO: markNeedsLayout should not imply markNeedsPaint in this case (or in layout builders in general). part1: #163575 diff this ... part1 LongCatIsLooong/flutter@OverlayPortal-always-add-to-dirty-list...LongCatIsLooong:flutter:OverlayPortal-paint-transform-builder ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This API allows the widget tree of an `OverlayPortal.overlayChild` to depend on various layout information (e.g. the incoming constraints, or the size of a RenderObject) from another child subtree of `Overlay` that does layout before the `overlayChild`. Most RenderObject subclasses can only access its child's or children's layout info, but not the layout info of its other descendants because of the "relayout boundary" optimization. Such locality makes the layout dependencies easier to reason about but it also makes it difficult to implement certain common UI patterns (see the examples in the description of the [previous PR](flutter#163575)) The API is currently only available on `OverlayPortal` as it is the only Overlay API (AFAIK) that guarantees every render object in a "path" within the render tree has finished doing layout. TODO: polish the API docs and code comments TODO: more tests? TODO: markNeedsLayout should not imply markNeedsPaint in this case (or in layout builders in general). part1: flutter#163575 diff this ... part1 LongCatIsLooong/flutter@OverlayPortal-always-add-to-dirty-list...LongCatIsLooong:flutter:OverlayPortal-paint-transform-builder ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This change makes
overlayChildunreachable via regular layout treewalk, so the paint transform fromOverlayPortal.childto the target overlay can be reliably computed during layout (assuming the paint transform of all nodes in the path are known during layout, see the comments below).This is part of the changes that will eventually (hopefully) enable an
OverlayAPI that allows an accessory view to change its size and location based on the main view's size and location in theOverlay(similar toCompositedTransform{Target, Follower}) .Notable use cases of such an API:
Overlay(and currently computing that has an 1-frame delay).This PR does not enable the API by itself, since the accessory view would need to be marked as needing relayout when the main view's paint transform within the
Overlaychanges. See <PR #TBD> for the implementation that marks the overlay child dirty when the paint transform changes.Differences between the new API and
CompositedTransform{Target, Follower}The new API's use cases largely overlap that of
CompositedTransform{Target, Follower}, but it additionally:CompositedTransformFollowercan only follow.CompositedTransformFollowerhas (that the CompositedTransformTarget must come earlier in the paint order than this CompositedTransformFollower).On the other hand:
Overlay. In rare cases the parentRenderObjectmay need the size of the follower (can't really think of one though).RenderFollowerLayerin the path, as its paint transform is only updated inaddToScene, way after the layout process is done. So it's a bit leaky since whether there's aRenderFollowerLayeris an implementation detail.I'll try to add asserts to catch the incompatibility. If the new API works then i'd expect it to significantly reduce the use of
CompositedTransformFollower.Part 2 of this PR: LongCatIsLooong/flutter@OverlayPortal-always-add-to-dirty-list...LongCatIsLooong:flutter:OverlayPortal-paint-transform-builder
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.