Skip to content

Commit

Permalink
Improve measure invalidation and legacy Layout(s) performance
Browse files Browse the repository at this point in the history
- Do not bubble up `MeasureInvalidated` on scrollable views and pages
- Do not synchronously measure/arrange children on legacy layout upon child measure invalidated: simply wait for the next native layout pass
  • Loading branch information
albyrock87 committed Aug 30, 2024
1 parent 5aae18c commit 5b65d84
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 36 deletions.
5 changes: 5 additions & 0 deletions src/Controls/src/Core/Items/ItemsView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,5 +224,10 @@ protected override void OnBindingContextChanged()
if (InternalItemsLayout is BindableObject bo)
SetInheritedBindingContext(bo, BindingContext);
}

internal override void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger)
{
// No need to trigger and propagate MeasureInvalidated given this is a scrollable area
}
}
}
5 changes: 5 additions & 0 deletions src/Controls/src/Core/ItemsView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,10 @@ static void OnItemsSourceChanged(BindableObject bindable, object oldValue, objec
}

protected virtual bool ValidateItemTemplate(DataTemplate template) => true;

internal override void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger)
{
// No need to trigger and propagate MeasureInvalidated given this is a scrollable area
}
}
}
15 changes: 5 additions & 10 deletions src/Controls/src/Core/LegacyLayouts/Layout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ protected virtual void InvalidateLayout()

internal override void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger)
{
base.OnChildMeasureInvalidatedInternal(child, trigger);

// TODO: once we remove old Xamarin public signatures we can invoke `OnChildMeasureInvalidated(VisualElement, InvalidationTrigger)` directly
OnChildMeasureInvalidated(child, new InvalidationEventArgs(trigger));
}
Expand Down Expand Up @@ -503,7 +505,7 @@ internal virtual void OnChildMeasureInvalidated(VisualElement child, Invalidatio
int count = children.Count;
for (var index = 0; index < count; index++)
{
if (LogicalChildrenInternal[index] is VisualElement v && v.IsVisible && (!v.IsPlatformEnabled || !v.IsPlatformStateConsistent))
if (LogicalChildrenInternal[index] is VisualElement { IsVisible: true } v && (!v.IsPlatformEnabled || !v.IsPlatformStateConsistent))
{
return;
}
Expand All @@ -517,20 +519,13 @@ internal virtual void OnChildMeasureInvalidated(VisualElement child, Invalidatio
{
return;
}
if (trigger == InvalidationTrigger.HorizontalOptionsChanged || trigger == InvalidationTrigger.VerticalOptionsChanged)
if (trigger is InvalidationTrigger.HorizontalOptionsChanged or InvalidationTrigger.VerticalOptionsChanged)
{
ComputeConstraintForView(view);
}
}

if (trigger == InvalidationTrigger.RendererReady)
{
InvalidateMeasureInternal(InvalidationTrigger.RendererReady);
}
else
{
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}
// Nothing else to do here: platform will take care of arranging the children if needed on the next layout pass
}

internal override void OnIsVisibleChanged(bool oldValue, bool newValue)
Expand Down
28 changes: 2 additions & 26 deletions src/Controls/src/Core/Page/Page.cs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ protected override void OnBindingContextChanged()

internal override void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger)
{
// TODO: once we remove old Xamarin public signatures we can invoke `OnChildMeasureInvalidated(VisualElement, InvalidationTrigger)` directly
// No need to trigger and propagate MeasureInvalidated considering Page is the root node
OnChildMeasureInvalidated(child, new InvalidationEventArgs(trigger));
}

Expand All @@ -510,8 +510,7 @@ internal override void OnChildMeasureInvalidatedInternal(VisualElement child, In
/// <param name="e">The event arguments.</param>
protected virtual void OnChildMeasureInvalidated(object sender, EventArgs e)
{
InvalidationTrigger trigger = (e as InvalidationEventArgs)?.Trigger ?? InvalidationTrigger.Undefined;
OnChildMeasureInvalidated((VisualElement)sender, trigger);
// Nothing to do here: platform will take care of arranging the children if needed on the next layout pass
}

/// <summary>
Expand Down Expand Up @@ -583,29 +582,6 @@ protected void UpdateChildrenLayout()
}
}

internal virtual void OnChildMeasureInvalidated(VisualElement child, InvalidationTrigger trigger)
{
var container = this as IPageContainer<Page>;
if (container != null)
{
Page page = container.CurrentPage;
if (page != null && page.IsVisible && (!page.IsPlatformEnabled || !page.IsPlatformStateConsistent))
return;
}
else
{
var logicalChildren = this.InternalChildren;
for (var i = 0; i < logicalChildren.Count; i++)
{
var v = logicalChildren[i] as VisualElement;
if (v != null && v.IsVisible && (!v.IsPlatformEnabled || !v.IsPlatformStateConsistent))
return;
}
}

InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}

internal void OnAppearing(Action action)
{
if (_hasAppeared)
Expand Down
5 changes: 5 additions & 0 deletions src/Controls/src/Core/ScrollView/ScrollView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -489,5 +489,10 @@ Size ICrossPlatformLayout.CrossPlatformArrange(Rect bounds)

return bounds.Size;
}

internal override void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger)
{
// No need to trigger and propagate MeasureInvalidated given this is a scrollable area
}
}
}

0 comments on commit 5b65d84

Please sign in to comment.