react-native-windows icon indicating copy to clipboard operation
react-native-windows copied to clipboard

Add method to invoke nested Yoga layout

Open rozele opened this issue 2 years ago • 6 comments

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

rozele avatar Jul 05 '22 15:07 rozele

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 avatar Jul 05 '22 17:07 asklar

@asklar - indeed - there's not really any alternative for this. I'll work up a sample at some point.

rozele avatar Jul 05 '22 19:07 rozele

We're considering other options for handling re-entrant / nested layout. Converting to draft for now.

rozele avatar Aug 15 '22 14:08 rozele

Note: dependent on #10422, leaving in draft state until #10422 is merged

rozele avatar Aug 22 '22 14:08 rozele

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.

  1. View added as descendant of Text in React JS
  2. TextViewManager or VirtualTextViewManager detects child in not Inline but some type of UIElement
  3. Node where child is added notifies TextViewManager that it needs to replace the native view with RichTextBlock
  4. View is added to RichTextBlock via InlineUIContainer
  5. On subsequent SetLayoutProps call, state in TextViewManager shadow node knows that we need to recursively invoke Yoga for the nested Views
  6. 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.

rozele avatar Aug 22 '22 15:08 rozele

Based on conversation with @asklar - moving to draft to confirm this does not break rn-xaml.

rozele avatar Aug 24 '22 19:08 rozele

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.

rozele avatar Oct 05 '22 19:10 rozele