dotnet / dotnet/maui

[Android] Scrolling inside shadowed containers regressed in 10.0.90

Open
#37,281 6 comments 2 reactions 0 assignees View on GitHub
area-drawing i/regression perf/general platform/android regressed-in-10.0.90 s/triaged s/verified t/bug
Dominant language
C#
Stars
23.3k
Forks
2k
Avg merge
1d 14h
Merged PRs (30d)
296

Description

### Description

Android scrolling inside a shadowed ancestor regressed between .NET MAUI 10.0.80 and 10.0.90. `CollectionView` and `ScrollView` content can become severely sluggish or temporarily blank because descendant updates repeatedly invalidate and redraw the entire shadowed container.

Original report:
https://www.reddit.com/r/dotnetMAUI/comments/1vjyyjn/net_10_scrolling_performance_issues_on_android/

Author reproduction:
https://github.com/MrLazyLee/ScrollPerformance

The public repository omitted several unrelated application types, so minimal local stubs were required to build it. The reported popup, bindings, resources, visual hierarchy, and scrolling content were left unchanged.

### Hidden hierarchy in the complete reproduction

The XAML excerpt in the Reddit post only showed the `CollectionView`, but the runnable hierarchy adds two large shadow wrappers around it:

1. CommunityToolkit `PopupOptions` supplies a default popup shadow.
2. `ChangeLogPopup.xaml` wraps the list in a `Border` using `Shadow="{StaticResource CenterShadow}"`.

The same root cause applies to the author's reported `ScrollView` replacement because it is not specific to virtualization.

### Faulty commit

The regression was introduced by #35623, release commit [`2e3d581d52a16ea1d30a6de8ff3b88dd23a1ace8`](https://github.com/dotnet/maui/commit/2e3d581d52a16ea1d30a6de8ff3b88dd23a1ace8).

That change made `PlatformWrapperView.onDescendantInvalidated()` call `invalidate()` for every descendant update whenever the wrapper has a shadow. The intended `Switch` fix needs a redraw when the immediate child animates, but scrolling descendants then force the whole popup and border wrappers to re-record their display lists for every item update.

Four automated up/down scroll cycles produced:

| Wrapper | Descendant invalidations | Immediate-child invalidations |
|---|---:|---:|
| Popup, 1079 x 1678 | 1,859 | 3 |
| Border, 1026 x 1306 | 1,803 | 2 |

Only five invalidations originated from immediate children; the other 3,657 caused unnecessary shadow-wrapper redraws.

#36988 fixes a separate software-shadow case involving a fully transparent border stroke. It does not cover this reproduction's opaque `#808080` stroke or the popup's fallback shadow path.

### Performance verification

The author reproduction was tested on the same Android emulator with the same automated eight-cycle scroll sequence and no screen recording. Control and fix AARs were built from the exact 10.0.90 source so the invalidation guard was the only functional difference.

| Variant | 50th percentile | 90th percentile | Slow UI-thread frames |
|---|---:|---:|---:|
| 10.0.80 | 34 ms | 53 ms | 29 |
| 10.0.90 control | 42-44 ms | 53-61 ms | 106-118 |
| 10.0.90 with fix | 34-38 ms | 57-61 ms | 28-47 |

The fix returns the reproduction to the 10.0.80 range.

### Videos

**10.0.80 baseline**

https://github.com/user-attachments/assets/4a7e8b4a-8ebd-499b-9477-718886608ab8

**10.0.90 regression**

https://github.com/user-attachments/assets/fc2dceb7-5f1f-4eae-9461-2c53fcc6bc90

**10.0.90 with fix**

https://github.com/user-attachments/assets/0ea77dab-5cd8-4cb5-956a-169c9b12c31b

### Fix

#37291 limits forced shadow redraws to invalidations from the wrapper's immediate child. Deeper descendants continue through their own Android RenderNodes, preserving the original `Switch` fix while avoiding full-container redraws during scrolling.

Contributor guide

Open the contributing guide

Research direction

Start at PlatformWrapperView.onDescendantInvalidated() and review the linked #37291 change alongside the 10.0.90 regression details. Build the author reproduction, run the automated eight-cycle scroll sequence, and compare shadowed CollectionView and ScrollView behavior with the reported 10.0.80 and fixed-build performance ranges.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, csharp
Domain
mobile, performance
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.