Layouting in iOS
The layouting cycle (measure and arrange) in Uno on iOS is a mingling of native layouting logic and logic in managed code. These interactions are summarized in the diagram below. This information is primarily intended to help when debugging Uno, but may also be useful when attempting to incorporate non-Uno views into the visual tree.
flowchart TD
%% ios layout flow
basesetneedslayout{{"base.SetNeedsLayout()"}}
layoutsublayers{{"CALayer.LayoutSublayers"}}
layoutsubviews["(override) FrameworkElement.LayoutSubviews()"]
subgraph Measure Invalidation
invalidate-arrange["UIElement.InvalidateArrange()"]
invalidate-measure["IFrameworkElementHelper.InvalidateMeasure()"]
setneedslayout["(override) FrameworkElement.SetNeedsLayout()"]
setsuperviewneedslayout["FrameworkElement.SetSuperviewNeedsLayout()"]
native.sizethatfits{{".SizeThatFits() called from parent element"}}
invalidate-arrange ==> invalidate-measure
invalidate-measure ==> setneedslayout
setneedslayout --> setsuperviewneedslayout
setsuperviewneedslayout -. on parent element.-> setneedslayout
setneedslayout ==> basesetneedslayout
end
subgraph Measure Phase
sizethatfits["(override) FrameworkElement.SizeThatFits(availableSize)"]
xamlmeasure["FrameworkElement.XamlMeasure(availableSize)"]
layouter.measure["Layouter.Measure(availableSize)"]
layouter.measureoverride["Layouter.MeasureOverride(availableSize)"]
measureoverride["FrameworkELement.MeasureOverride(availableSize)<br><em>overridden by element</em>"]
appmeasureoverrride[["local implementation of MeasureOverride(availableSize)<br>"]]
subgraph Subelement measuring
measureelement["FrameworkElement.MeasureElement(child)"]
layouter.measureelement["Layouter.MeasureElement(child)"]
measurechildoverride["Layouter.MeasureChildOverride"]
measureelement ==> layouter.measureelement
layouter.measureelement ==> measurechildoverride
end
sizethatfits ==> xamlmeasure
xamlmeasure ==> layouter.measure
layouter.measure ==> layouter.measureoverride
layoutsubviews ==> xamlmeasure
layouter.measureoverride ==> measureoverride
measureoverride ==> appmeasureoverrride
appmeasureoverrride -- for child elements --> measureelement
end
basesetneedslayout -. "schedule for next loop (native)" .-> layoutsublayers
layoutsublayers ==> layoutsubviews
native.sizethatfits ==> sizethatfits
measurechildoverride ==> sizethatfits
frame -. "internal scheduling for next loop (native)" .-> layoutsublayers
subgraph Arrange Phase
layouter.arrange["Layouter.Arrange(finalRect)"]
arrangeoverride["FrameworkElement.ArrangeOverride(finalSize)"]
frame{{".Frame property set"}}
subgraph for child elements
arrangeelement["Framework.ArrangeElement(child)"]
layouter.arrangeelement
app.arrangeoverride[["(override) ArrangeOverride(finalSize)"]]
layouter.arrangechild
layouter.arrangechildoverride
end
layouter.arrange ==> arrangeoverride
arrangeoverride ==> app.arrangeoverride
app.arrangeoverride ==> arrangeelement
arrangeelement ==> layouter.arrangeelement
layouter.arrangeelement ==> layouter.arrangechild
layouter.arrangechild ==> layouter.arrangechildoverride
layouter.arrangechildoverride ==> frame
layoutsubviews ==> layouter.arrange
end
subgraph legend
direction LR
uno-legend["Uno methods"]
native-legend{{"Native (iOS) methods"}}
application-legend[["Application/Framework implementation"]]
end