react-native-windows
react-native-windows copied to clipboard
Add method to invoke nested Yoga layout
Description
Type of Change
Erase all that don't apply.
- New feature (non-breaking change which adds functionality)
Why
Yoga does not recurse layout beyond a node that provides a self-measurement function. If you want to build a custom control that allows for XAML layout with descendants from React that still use Yoga layout, you need to kick off a new layout calculation from each "inner root".
Resolves #7601
What
This change adds an API to XamlUIService to kick off Yoga layout from any React tag, allowing custom controls to, for example, override MeasureOverride in a "self-measuring" XAML component and invoke XamlUIService::LayoutElement to trigger the nested Yoga calculation.
The main limitation with this approach is that XAML is likely to draw the layout changes in two separate passes, the first pass draws from the React root to the self-measuring view, and because the Width/Height/Top/Bottom properties get set for the "inner root" and it's descendants, these will require a separate layout and draw pass by XAML to commit.
Microsoft Reviewers: Open in CodeFlow
I think in order to use this API, your native VM must implement a panel so that you can override layout, is that right? can you provide a sample of how this API is to be used? Ideally if you just want to have a native VM for e.g. a XAML Grid, you shouldn't need to declare a subclass of Grid just so that you can override measure/arrange
@asklar - indeed - there's not really any alternative for this. I'll work up a sample at some point.
We're considering other options for handling re-entrant / nested layout. Converting to draft for now.
Note: dependent on #10422, leaving in draft state until #10422 is merged
Please note, this change is also going to be useful should we ever support nested Views in Text with RichTextBlock, as we'll need an option to invoke Yoga layout on a specific sub-tree from TextViewManager.
@asklar - this is the best example I can think of without adding a custom VM to playground. We don't have any such examples yet, so not planning on setting that up for this PR. The sequence of events would look something like the following to implement nested Views in Text.
- View added as descendant of Text in React JS
- TextViewManager or VirtualTextViewManager detects child in not Inline but some type of UIElement
- Node where child is added notifies TextViewManager that it needs to replace the native view with RichTextBlock
- View is added to RichTextBlock via InlineUIContainer
- On subsequent
SetLayoutProps
call, state in TextViewManager shadow node knows that we need to recursively invoke Yoga for the nested Views - Nodes in Text inline tree are visited, when we hit an InlineUIContainer, we invoke
ApplyYogaLayout
on NativeUIManager.
Another good thing to note is that this type of thing is already supported on the public surface for Android and iOS view managers / shadow nodes, so strictly speaking it's a bug / gap that we don't support this in RNW.
Based on conversation with @asklar - moving to draft to confirm this does not break rn-xaml.
This is a net new API, should not impact react-native-xaml. Lifting out of draft. Please note, this API is mostly useless without #10761.