-
Notifications
You must be signed in to change notification settings - Fork 26.7k
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
Attach an Element's render object to a designated OverlayEntry #39104
Attach an Element's render object to a designated OverlayEntry #39104
Conversation
8029459
to
8ca93a6
Compare
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.
Some comments I noticed during the initial read-through.
@@ -54,8 +54,8 @@ class AbstractNode { | |||
@protected | |||
void redepthChild(AbstractNode child) { | |||
assert(child.owner == owner); | |||
if (child._depth <= _depth) { | |||
child._depth = _depth + 1; | |||
if (child.depth <= depth) { |
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.
Why this change?
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.
the default implementation of redepthChild
should respect AbstractNode.depth
overrides so the minDepth
trick in _RenderFollowerProxyBox
works
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.
That will probably have painful performance implications (moves this from a simple jmp to an indirect jump).
@@ -563,6 +564,9 @@ class _TheatreElement extends RenderObjectElement { | |||
void visitChildren(ElementVisitor visitor) { | |||
if (_onstage != null) | |||
visitor(_onstage); | |||
if (_offstage == null) |
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.
When would you call visitChildren while _offstage is still null? Should this be an assert?
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 ran into this issue #37161 when I was poking around. Probably was trying to print the overlay before it was mounted and toString()
threw.
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.
let's resolve this in a separate PR
final _RenderLeaderProxyBox leaderRenderBox; | ||
} | ||
|
||
/// An [OverlayEntry] that allows an [OverlayConduit] to attach its |
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.
This probably needs a better doc comment explaining when and for what this should and shouldn't be used.
final GlobalKey _mountPointKey; | ||
_PendingRenderObjectManifest _pendingRenderObject; | ||
|
||
@visibleForTesting |
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.
Move this annotation to after the comment.
&& element == other.element; | ||
} | ||
|
||
// We're not hashing this anyways. |
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.
This comment doesn't seem useful.
/// to the designated [ProxyOverlayEntry] [overlayEntry]. | ||
const OverlayConduit({ | ||
Key key, | ||
this.overlayItem, |
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: overlayChild
to make it clear that this is the child that goes into the overlay?
assert(overlayItem == null || overlayEntry != null), | ||
super(key: key); | ||
|
||
/// A widget whose render object will be attached onto [overlayEntry]. |
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.
A widget that is build like a regular child, but visually appears in the [overlayEntry].
The widget is build in the build context of this widget, but its render object is attached to the overlayEntry.
} | ||
|
||
@immutable | ||
class _OverlaySlot { |
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.
If the slot's identity is only defined by the element - can you just use the element as slot?
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.
_OverlayConduitElement
used to have no render object (similar to a ComponentElement
) so I added this class to differentiate the overlayChild
slot and the child
slot. I guess it's safe to get rid of it now.
void forgetChild(Element child) { | ||
if (child == _child) | ||
child = null; | ||
assert(child == _overlayItem); |
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.
This is strange: The only child we can forget is the overlayItem? What about the child child? Can those not be different?
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.
Or is the if missing a return maybe? (If so, we should add a test that fails without it)
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.
oh it's missing a return. Thanks for catching that!
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.
child = null;
didn't know it was possible 👀
// If mountPoint is already built. | ||
assert(mountPoint.renderObject != null); | ||
mountPoint.renderObject.leader = renderObject; | ||
mountPoint.insertChildRenderObject(child, slot); |
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.
Does this one have multiple slots? Can slot just be null?
@LongCatIsLooong Any chance you can merge this to tip of tree? I tried checking out the branch but I got a lot of merge conflicts. |
So I tried this out yesterday and by and large it seems to work as expected (which is impressive! Wow!). However, I think we need to separate out the conduit API from Overlay. Having them be tied too closely leads to all kinds of problems, for example you can't use Positioned in the overlayChild. The other weird thing about this API is that if you have multiple children you want to move to elsewhere in the tree you need one widget for each one. That took me a while to understand. Once I got the hang of it I was able to work with that easily enough. Here's the code I wrote to experiment with this: http://junkyard.damowmow.com/606 I think I need to do more experiments, but I'd like to wait to have a version that isn't tied to the Overlay before I do that. |
f36d8b6
to
6f2d077
Compare
|
||
import 'framework.dart'; | ||
|
||
// When an OverlayConduit tries to mount its overlayItem onto its overlayEntry's |
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.
looks like the comments need updating
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.
done
2cef766
to
0db2ab9
Compare
any updates? Can we merge this? |
Oh ok, I see it's just in progress :) gtk |
_RenderLeaderProxyBox([RenderBox child]) : super(child); | ||
|
||
_RenderFollowerProxyBox __follower; | ||
_RenderFollowerProxyBox get _follower => __follower; |
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.
nit: since the class is private, the member can be public. this lets you avoid the double-underscore thing.
I like this new approach. I need to try playing with it. |
@LongCatIsLooong points out for (3) that when the Leader is pushed down, its nodes are (temporarily) removed from the tree which also removes the children from the Follower, so it actually reduces to case (1). So really all we need to do is make sizedByParent prevent the layout() call from laying out the children immediately. |
Looking at the test failures, this probably requires a rebase to make cirrus happy. |
1ebdede
to
1c61cb4
Compare
@Hixie @goderbauer I tried out the "throw It seems some render objects need not only the size of their child but also the child's layout, e.g. render objects that call their child's |
|
@LongCatIsLooong Do you think there still is a path forward for this PR? Are you still working on it? |
Yes I'm still (not very actively) working on this. I think it may still be doable, just need to find an approach that requires less crazy framework changes. |
3e1c937
to
4b6adf1
Compare
4b6adf1
to
af596b1
Compare
@Hixie @goderbauer all the tests seem to be passing now. Could you take a look? I added a |
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 the depthbarrier, if i understand correctly, it is trying to prevent the attached children under conduit anchor to be laid out before the anchor. If that is the intention, have you checked out this https://github.com/rrousselGit/flutter_portal/blob/rework/lib/src/portal.dart?
This is @rrousselGit attempt to deal with this problem and i think it worth considering. The goal is the conduit widget is not responsible for laying out or paint its remote child. It merely attach its remote child to the anchor key. When the conduit anchor layout, it pick up the anchor key and see which children it has and proceed to layout and paint them. The entire discussion can be found in #50961
Besides the comment, I have a general question, It seems like the attempt here is to wrapped the overlay with conduit and conduitanchor to provide declarative overlay api. The portal is trying to achieve the same thing except it replace the overlay with an entire different system Portal
. Why do we prefer one over the other?
/// | ||
/// The [dependent] must be [attached], has the same [PipelineOwner] as this | ||
/// [RenderObject], and its [shouldDeferLayout] and [sizedByParent] must be true. | ||
/// Additionally To prevent introducing circular dependencies, [dependent]'s |
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.
/// Additionally To prevent introducing circular dependencies, [dependent]'s | |
/// Additionally to prevent introducing circular dependencies, [dependent]'s |
class _RenderConduit extends RenderProxyBox { | ||
_RenderConduit([RenderBox child]) : super(child); | ||
|
||
_RenderConduitAnchor _follower; |
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 confused by the name. If i read it correctly, shouldn't the Conduit be follower and ConduitAnchor be the leader because conduit attach its child the conduitanchor?
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.
The anchor is named follower in the sense that it depends on its conduit. The anchor changes if its conduit changes, but not the other way around. I guess dependent/dependency sounds good here too.
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.
The problem with naming the anchor follower is that you then have one follower with multiple leaders which is counterintuitive. Usually there should only be one leader with multiple followers. The dependent/dependency sounds good
I can answer that question: Although if it were to be merged into Flutter, it could still be valuable to separate them, to help the migration. |
In the The conduit does the layout of the overlay entry (where the constraints are obtained with an object equivalent to Although I'm not sure if this has undesired side-effects |
@rrousselGit Thanks for the explanation! I think the current implementation in the rework branch will probably break |
It did, but I managed to fix it (it's in the branch) My biggest worry was about RepaintBoundary & co, wondering if there isn't an edge case where the UI doesn't refresh or something Haven't found anything so far though. |
Are you giving up on this?
…On Fri, Jun 19, 2020, 22:32 LongCatIsLooong ***@***.***> wrote:
Closed #39104 <#39104>.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#39104 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AEZ3I3ITSE5M6G6WT4TFIB3RXPKNHANCNFSM4IO4OPUA>
.
|
@rrousselGit no I'm just trying to reduce the number of open PRs since I'm currently not working on this. |
What remains to be done? Between Hero/package:animation issues, state restoration, and provider having difficulties, I think it's quite important and may continue it myself. |
Description
This PR adds a new widget
OverlayConduit
that manages a regular child and anoverlayItem
child. When mounted, theoverlayItem
child has the same behavior as the regular child, except that it attaches its render object to the designatedoverlayEntry
. Thus theoverlayItem
gets its inherited widgets from the currentBuildContext
, as the regular child does. This also guarantees that when the entireOverlayConduit
subtree unmounts, the removal of listeners and invocation ofState.dispose
will proceed in an orderly fashion: the deepest elements get removed/disposed of first, preventing #35555 from happening.Classes in this PR, in a typical setting
Related Issues
#36220
Tests
I added the following tests:
packages/flutter/test/widgets/overlay_conduit_test.dart
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?