Skip to content

Improve iOS CollectionView performance by leveraging the new platform level invalidation mechanism #28225

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

Conversation

albyrock87
Copy link
Contributor

@albyrock87 albyrock87 commented Mar 6, 2025

Description of Change

This is the second part of #25664 which leverages the work done in #26629.

The PR gets rid of MeasureInvalidated subscription and fixes CV2 handler so that TemplatedCell2 can react to content size changes.

You can see this by using "Item Size Gallery" for CollectionView.

Using #25671 UI test I've been able to measure the benefits of this PR over main branch.
Please note no-resize on CV2 main (as item size detection was not implemented).

Branch Handler Measure Arrange
main CV1 525 308
PR CV1 221 231
main CV2 (no-resize) 1371 347
PR CV2 338 379

To highly reduce measurements I've marked the TemplatedCell*.ContentView with a Tag that treats it as kind-of-ICrossPlatformLayoutBacking so that the contained MauiView/LayoutView treats it as IsFinalMeasureHandledBySuperView and avoids remeasuring its content with the applied Bounds on LayoutSubviews.

Issues Fixed

Fixes #25650
Fixes #25391

Videos of AllTheLists

Captured using a modified version of https://github.com/davidortinau/AllTheLists.git compiled in Release mode with a constant number of lessons generated (high number).

challenging.patch

Using CV1

PR-25664-CV1-AllTheLists.mp4

Using CV2

PR-25664-CV2-AllTheLists.mp4

@albyrock87 albyrock87 requested a review from a team as a code owner March 6, 2025 15:19
@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Mar 6, 2025
@jsuarezruiz jsuarezruiz added area-controls-collectionview CollectionView, CarouselView, IndicatorView t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf) collectionview-cv2 labels Mar 6, 2025
@jsuarezruiz
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

Copy link
Contributor

@jsuarezruiz jsuarezruiz left a comment

Choose a reason for hiding this comment

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

Voy a hacer un reintento pero el test CollectionShouldInvalidateOnVisibilityChange esta fallando con un crash en iOS.

The app was expected to be running still, investigate as possible crash

Could be related with the changes?

@albyrock87 albyrock87 force-pushed the avoid-using-measure-invalidate-in-collectionview branch from 25d9ddc to ad15928 Compare March 7, 2025 12:38
@albyrock87 albyrock87 marked this pull request as draft March 7, 2025 12:40
@PureWeen
Copy link
Member

PureWeen commented Mar 7, 2025

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

{
if (size.IsCloseTo(_currentSize))
if (size.IsCloseTo(_currentSize) && !forceUpdate)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When used as ContentPage.Content = new CollectionView() the _currentSize never changes so this code path was not hit on the first LayoutSubviews, leading to wrong preferredAttributes computation and bad cell positioning.
You can verify this on main by testing out Issue13203 where the text is being positioned in the middle behind the safe area instead of being left aligned.

@@ -193,18 +194,37 @@ public override void LoadView()
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
ConstrainItemsToBounds();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This makes no sense here because bounds are not set yet: they'll be in ViewWillLayoutSubviews.
So any computation made here cannot be trustworthy.

Copy link
Member

Choose a reason for hiding this comment

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

If we navigate from a CV page to a new page and then back to the CV sometimes ViewWillLayoutSubviews will not always trigger.

Copy link
Contributor Author

@albyrock87 albyrock87 Mar 25, 2025

Choose a reason for hiding this comment

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

Interesting, but why is it necessary to trigger this method again considering the view was already laid out before pushing the new page? @rmarinho

@albyrock87 albyrock87 force-pushed the avoid-using-measure-invalidate-in-collectionview branch 2 times, most recently from 3a4813d to 4a71e68 Compare March 10, 2025 11:45
@albyrock87 albyrock87 force-pushed the avoid-using-measure-invalidate-in-collectionview branch from 4a71e68 to 10e4731 Compare March 10, 2025 14:28
@albyrock87 albyrock87 force-pushed the avoid-using-measure-invalidate-in-collectionview branch from da31518 to 025e9ad Compare March 10, 2025 17:04
@PureWeen PureWeen added this to the .NET 9 SR6 milestone Mar 10, 2025
@PureWeen PureWeen moved this from Todo to In Progress in MAUI SDK Ongoing Mar 10, 2025
@PureWeen PureWeen added the p/0 Work that we can't release without label Mar 10, 2025
@albyrock87
Copy link
Contributor Author

@jsuarezruiz done, you can run AZP again

@jsuarezruiz
Copy link
Contributor

/azp run

@albyrock87 albyrock87 marked this pull request as ready for review March 22, 2025 15:00
@PureWeen PureWeen moved this from In Progress to Ready To Review in MAUI SDK Ongoing Mar 22, 2025
}
}

if (invalidatedPaths != null)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (invalidatedPaths != null)
if (invalidatedPaths is not null)

Copy link
Member

Choose a reason for hiding this comment

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

or is null return here

@dotnet dotnet deleted a comment from PureWeen Mar 24, 2025
@dotnet dotnet deleted a comment from azure-pipelines bot Mar 24, 2025
@dotnet dotnet deleted a comment from PureWeen Mar 24, 2025
@dotnet dotnet deleted a comment from azure-pipelines bot Mar 24, 2025
@dotnet dotnet deleted a comment from azure-pipelines bot Mar 24, 2025
@dotnet dotnet deleted a comment from PureWeen Mar 24, 2025
@dotnet dotnet deleted a comment from azure-pipelines bot Mar 24, 2025
@@ -37,6 +37,7 @@ protected void InitializeContentConstraints(UIView platformView)
ContentView.TrailingAnchor.ConstraintEqualTo(TrailingAnchor).Active = true;

// And we want the ContentView to be the same size as the root renderer for the Forms element
// TODO: we should probably remove this to support `Margin` applied to the cell's root `VirtualView`
Copy link
Member

Choose a reason for hiding this comment

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

We should create a new issue for this, maybe for net10.0

@github-project-automation github-project-automation bot moved this from Ready To Review to Approved in MAUI SDK Ongoing Mar 25, 2025
@rmarinho rmarinho merged commit 609499c into dotnet:main Mar 25, 2025
138 checks passed
@github-project-automation github-project-automation bot moved this from Approved to Done in MAUI SDK Ongoing Mar 25, 2025
@PureWeen
Copy link
Member

/backport to inflight/candidate

Copy link
Contributor

Started backporting to inflight/candidate: https://github.com/dotnet/maui/actions/runs/14072653418

Copy link
Contributor

@PureWeen backporting to "inflight/candidate" failed, the patch most likely resulted in conflicts:

$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Applying: Use native invalidation mechanism to detect TemplatedCell size change.
Using index info to reconstruct a base tree...
M	src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs
M	src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs
Falling back to patching base and 3-way merge...
Auto-merging src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs
CONFLICT (content): Merge conflict in src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs
Auto-merging src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs
CONFLICT (content): Merge conflict in src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0001 Use native invalidation mechanism to detect TemplatedCell size change.
Error: The process '/usr/bin/git' failed with exit code 128

Please backport manually!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-controls-collectionview CollectionView, CarouselView, IndicatorView collectionview-cv2 community ✨ Community Contribution p/0 Work that we can't release without t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf)
Projects
Status: Done
5 participants