-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
<ScrollView>
lags and stutters when many <Label>
Text updates happen periodically while trying to scroll on physical iOS
device
#19938
Comments
<ScrollView>
lags and stutters when one or more label updates happen periodically while trying to scroll<ScrollView>
lags and stutters when one or more <Label>
Text updates happen periodically while trying to scroll
<ScrollView>
lags and stutters when one or more <Label>
Text updates happen periodically while trying to scroll<ScrollView>
lags and stutters when many <Label>
Text updates happen periodically while trying to scroll on physical iOS
device
So looking at this, I think the underlying issue you're having is complex, but IMO it's partially your implementation. System.Timers.Timer invokes a new background thread. As that's off the UI Thread, you then invoke the UI Thread to update the text. As your example shows, if you turn off updating the actual Labels, the performance for scrolling is fine. However, your performance tanks before you even touch scrolling. Simulator.Screen.Recording.-.iPhone.15.-.2024-01-17.at.18.17.31.mp4Using my FPS counter library, I believe your frame rate gets cut in half by updating any part of your UI. The ScrollView itself isn't the issue though. If you remove the scroll view, but keep your component, the total FPS goes down regardless, all be it not as much, to about 45 to 50 FPS. The frame rate issues your seeing has nothing to do with scrolling... I think the root of your issue is that TestComponent. That isn't a virtualized control, so you have a thousand labels in a stack layout, all rendered at the same time. I think what is happening is that, by you doing that, whenever you invoke an action in the UI to update it, MAUI is recalculating the iOS Constraints for every single label in that StackLayout. Again, this has nothing to do with the ScrollView or scrolling. That's just a byproduct of the FPS being hit by the UI Calculations. Reducing the StackLayout items to 100 or 200, and performance remained at 60 FPS. Above that, it starts to go down... Now, if I'm correct on that, this might be a bug in MAUI, since that may not be necessary given the context to recalculate all of the iOS Constraints for the underlying views. But, realistically, if you have lots of items like this, you should use a Virtualized List component like ListView or CollectionView. Even if your current implementation works for other platforms, you're probably going to get a good reduction in memory usage by switching to a virtualized control. Simulator.Screen.Recording.-.iPhone.15.-.2024-01-17.at.18.56.39.mp4Switching out your StackLayout for a ListView, and performance is rock solid. @PureWeen What do you think? |
@drasticactions - Thanks Tim! I greatly appreciate your time spent reviewing this and your willingness to share your expertise!One point to note here is my real world use case is I have a large application that has a timer tick every 500ms and I display 3 timers at the top of the page always and at different intervals. I do work like popup reminders every 2 minutes, do autosaves every 3 seconds, refresh various views every 3 seconds...Where I see the greatly reduced framerate is not while scrolling a list of numbers or strings but just scroll views where there may not be more than just a like 2 screenfuls to scroll - made up of multiple controls nested into one view where each has lots of labels to display with associated values in other labels. I can't do virtualized.
Something just feels very wrong there and I have no foreseeable workaround. Thanks again for all your assistance and time!I remain a massive fan of .NET Maui and have been a .NET developer for over 20 years now. Before that, 20 years of C and C++ development.Thanks for helping move .NET Maui forward!Craig |
Is there a recommendation for a different timer to use within the .NET Maui Shell app as a timer a couple times a second to drive periodic tasks and to update/refresh the UI, do autosaves, etc that will not have the same frame rate impact? |
@schlaman Your issue isn't the Timer. You could switch it to any of the other .NET Timers and you would hit the same issue. If you remove the huge StackLayout and rerun the project with my FPS Viewer, it would be at 60fps. Again, the timer is not the issue. Nor is the ScrollView. The issue, as far as I can tell, is having an extremely large set of UI objects loaded while then manipulating items on the UI Thread. MAUI uses UIKit for building its UI for iOS and Mac (Via Catalyst), and it uses the UIKit AutoLayout system for handling layout between native views. With your current layout, MAUI is creating tons of UILabel/UITextView objects and then building constraints between them. When you then update your top labels with new text, this, I believe (I could be wrong here), causes a cascading effect where every constraint is then being recalculated and redrawn. Since you have thousands of items, all loaded in memory and on the page, while then doing updates to the UI every 100 milliseconds, that causes the performance hit (That's why the FPS goes down without you touching anything. It's a lot of CPU activity). It's also why it only happens in iOS and not Android or Windows, since those handle native layout very differently. This is why I said this may be a bug in MAUI (if my understanding of the issue is correct, which it may not be), since it probably doesn't need to recalculate and layout the entire UI by calling on UIKit to do so. But in a real world application, having that many objects loaded in a ScrollView as in your sample, IMO, isn't realistic. If you are building lists similar to how you wrote it in your sample, switching to a ListView or CollectionView should get you a performance and memory boost by having it be virtualized. It may help to make a new sample with a more realistic version of the UI you're building (and why it can't use a ListView or CollectionView) may help to where there are issues in MAUI. CC @tj-devel709, as I think you know iOS far better than I do, maybe you have ideas? |
Verified this issue with Visual Studio 17.10.0 Preview 4 (8.0.0-rc.2.9530 & 8.0.20).I can repro it on iOS platform |
Description
I created a test app to demonstrate that if you attempt to have a
<ScrollView>
and items to scroll, even just a bunch of labels with no binding or computations/lookups involved then there is significant lag/stuttering IF you frequently updated SomeLabelField.Text value while scrolling.In my example, I have a
<Grid>
and I have the<Label>
controls that I update with a timer at an interval of 100ms. Even at 500ms you see bad lag.Must deploy to physical iOS device to demonstrate issue.
This is an issue on a physical iOS device. Not sure about Android. In Windows it is not an issue at all.
Steps to Reproduce
Use the TimerLagTest app I created. It is in the public repro link below.
Deploy to a physical iOS device
The lag is quite noticeable on an iPhone Xs Max and an iPad Mini Gen 6
Deploy as debug (When deployed in Release mode the lag is way less noticeable but still occurs)
ONLY
thing not happening are the SomeLabel.Text="..." calls.Notice that the scrolling now is completely smooth again.
You can see it is not the timer that is causing the jerkiness or the function calls. It is purely the fact that a label is being updated that causes the jerkiness/lag in scrolling. In my real work example I even put in code to multiply like a million numbers in the timer tick event and there was no jerkiness. It is purely the act of just updating a label that KILLS the scrolling performance!!
Link to public reproduction project repository
https://github.com/schlaman/TimerLagTest
Version with bug
8.0.3
Is this a regression from previous behavior?
Not sure, did not test other versions
Last version that worked well
Unknown/Other
Affected platforms
iOS
Affected platform versions
iOS 17.1
Did you find any workaround?
No workaround found
Relevant log output
No response
The text was updated successfully, but these errors were encountered: