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

Set properties to null when none are available #5986

Merged
merged 5 commits into from
Jul 17, 2023

Conversation

CoderDake
Copy link
Contributor

Addresses #5933

Certain multi view widgets don't have layout properties so the layout explorer wasn't updating properly.
This PR sets the properties to null when none are available and add's some state to communicate that to the layout explorer.

Before Fix

Screen.Recording.2023-07-05.at.11.18.03.AM.mov

After Fix

Screen.Recording.2023-07-05.at.11.16.26.AM-FIXED.mov

@kenzieschmoll
Copy link
Member

@jacob314 if I remember correctly, if a widget doesn't have any layout properties, is the layout explorer supposed to show the layout properties for its closest ancestor?

@CoderDake CoderDake requested a review from a team as a code owner July 5, 2023 17:18
@CoderDake CoderDake requested review from kenzieschmoll and removed request for a team July 5, 2023 17:18
@CoderDake
Copy link
Contributor Author

@kenzieschmoll

if I remember correctly, if a widget doesn't have any layout properties, is the layout explorer supposed to show the layout properties for its closest ancestor?

This sound familiar based on some code that I stumbled upon, it was causing some weird behaviour since all of the parents here don't have layout data.

If it turns out that null properties is an expected behaviour then I could look at this a bit deeper to see if I could be more specific to only show the message if no parents have layout info either.

@jacob314
Copy link
Contributor

jacob314 commented Jul 6, 2023

@jacob314 if I remember correctly, if a widget doesn't have any layout properties, is the layout explorer supposed to show the layout properties for its closest ancestor?

That is correct. In general I thought that happened automatically as each Element got an associated RenderObject even if that was just the one shared with its ancestor.

@jacob314
Copy link
Contributor

jacob314 commented Jul 6, 2023

Perhaps this changed with @goderbauer's refactors to support multiple windows. We should rethink what makes sense. Generally what we are looking for is just the RenderObject that best approximates the space the widget takes up. Potentially now we need to go down the tree instead of up but would be good to have a principled design in what we are trying to do. Some special cases like Root might no longer have a real size given multiple windows and that is fine.

@goderbauer
Copy link
Member

goderbauer commented Jul 6, 2023

With the multi view changes it makes sense that some widgets do not have layout properties anymore. Prior to this change, every element always had an associated render object (i.e. Element. findRenderObject() would always find something). Since RenderObjects define the layout, you could say that each element had layout properties.

In the multi view world some parts of the widget tree are no longer backed by render objects. This is due to the fact that we have a single unified widget tree describing the content for all views. To this widget tree, multiple render trees (one for each view) are attached, but some widgets/elements may not have a render object at all (and Element. findRenderObject() will return null for those). Here is an example widget tree to illustrate:

MyDataProvider(
  data: _myAppData,
  child: ViewCollection(
    views: <Widget>[
      View(
        view: <...>
        child: ColoredBox(color: Colors.green),
      ),
      View(
        view: <...>
        child: ColoredBox(color: Colors.blue),
      ),
    ],
  )
);

This is a single widget tree defining the content of two Views (one green, one blue). The View widgets each bootstrap their own render trees, so if we were to call debugDumpRenderTree on this app, we would see two render trees looking something like this:

// render tree #1
RenderView#1
  _RenderColoredBox(color: green)

// render tree #2
RenderView#2
  _RenderColoredBox(color: blue)

The widgets above the View widgets (here: MyDataProvider and ViewCollection) don't define any layout aspects of the app, they are just there to inject some data (MyDataProvider) and to give our views anchor points in the widget tree (ViewCollection). You also can't associate them with a single render object (would you chose RenderView#1 or #2)? Neither choice makes sense here because while they organize those RenderObjects, they don't take on their layout properties. In other words, ViewCollection and MyDataProvider don't occupy any space in the app's layout.

tl;dr: It makes sense to me to disable the layout explorer for widgets that are not backed by a render tree (i.e. widgets that appear above the start of the render tree). The signal I would use is does Element.findRenderObject return null or not?

@goderbauer
Copy link
Member

Note, though, that I would expect widgets that are clearly part of a render tree to still show the layout explorer. For example, if the MyDataProvider from the previous example were to be used inside a View...

View(
  view: <..>
  child: MyDataProvider(
    data: <..>
    child: SizedBox(),
  ),
);

... I would expect that the layout explorer shows me the layout properties of the SizedBox render object even when I select MyDataProvider (that's also the renderobject that findRenderObject called on MyDataProvider's element would return). Here, MyDataProvider is part of the layout of this app.

@CoderDake
Copy link
Contributor Author

Note, though, that I would expect widgets that are clearly part of a render tree to still show the layout explorer. For example, if the MyDataProvider from the previous example were to be used inside a View...

View(
  view: <..>
  child: MyDataProvider(
    data: <..>
    child: SizedBox(),
  ),
);

... I would expect that the layout explorer shows me the layout properties of the SizedBox render object even when I select MyDataProvider (that's also the renderobject that findRenderObject called on MyDataProvider's element would return). Here, MyDataProvider is part of the layout of this app.

@jacob314 I've recreated goderbauer's provider example here and noticed that we The parent of the builder is the context that we see, not the child.

I've grabbed a screenshot to show what it looks like, does this look like it is working like you would expect it?

Screenshot 2023-07-13 at 5 11 37 PM

@goderbauer
Copy link
Member

I think this matches my expectation, yes. (I think in my original comment I had up and down mixed up, showing the parent is the right thing, though)

@jacob314
Copy link
Contributor

If you select a widget thats parent is a Row/Column we show that parents and its children. What we try to do is highlight the child that you selected but we clearly aren't doing a good job in that case. Seems like the vertical scroll in the layout explorer is off so you can't see that the child it is scrolled to is the ValueListenableBuilder.
What we are trying to do is explain why the ValueListenableBuilder is laid out the way it is and to do that we need to show how it is arranged in the Column.

Copy link
Contributor

@jacob314 jacob314 left a comment

Choose a reason for hiding this comment

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

lgtm

@CoderDake CoderDake merged commit 0a8cb6c into flutter:master Jul 17, 2023
15 checks passed
@CoderDake CoderDake deleted the multi-layout-explorer2 branch July 17, 2023 19:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants