microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.31k stars 676 forks source link

ItemsRepeater and ScrollView jumping back and forth #9308

Open christosk92 opened 8 months ago

christosk92 commented 8 months ago

Describe the bug

This has been an issue for as long as I can remember, I always thought it would be fixed one way or another but now I decided to report a bug on it.

I have a nested ItemsRepeater with the following layout:

   <ItemsRepeater ItemsSource="{x:Bind Discography, Mode=OneWay}">
       <ItemsRepeater.Layout>
           <StackLayout Orientation="Vertical" Spacing="8" />
       </ItemsRepeater.Layout>
       <ItemsRepeater.ItemTemplate>
           <DataTemplate x:DataType="artist:WaveeArtistDiscographyGroupViewModel">
               <Grid>
                   <Grid.RowDefinitions>
                       <RowDefinition Height="Auto" />
                       <RowDefinition />
                   </Grid.RowDefinitions>

                   <TextBlock
                       FontSize="16"
                       FontWeight="SemiBold"
                       Text="{x:Bind Name}" />

                   <ItemsRepeater
                       Grid.Row="1"
                       ItemsSource="{x:Bind Items}" />
               </Grid>
           </DataTemplate>
       </ItemsRepeater.ItemTemplate>
   </ItemsRepeater>

Surrounded with a ScrollView (not ScrollViewer !). Scrolling is fine and smooth (this has been improved over time !) until the end where the scroller glitches and you can see this jumping back and forth effect. (Video below)

Steps to reproduce the bug

1) Create a nested ItemsRepeater layout with a lot of times. 2) Surround with ScrollView. 3) Scroll to end and observe the bug

Expected behavior

No buggy scrolling !

Screenshots

https://github.com/microsoft/WindowsAppSDK/assets/13438702/020a8b3d-36ff-41ff-8580-a2e0b392ada8

NuGet package version

Windows App SDK 1.5 Experimental 2: 1.5.240124002-experimental2

Packaging type

Packaged (MSIX)

Windows version

Windows 10 version 22H2 (19045, 2022 Update)

IDE

Visual Studio 2022-preview

Additional context

No response

christosk92 commented 8 months ago

PS: The issue does not occur when scrolling with the scrollwheel.

github-actions[bot] commented 8 months ago

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one. Thank you!

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

ranjeshj commented 7 months ago

@christosk92 the outer repeater does not know the extent. It is making estimates on what it could be depending on the size of the groups it has seen so far and the number of groups. If the groups are of widely varying sizes, then it is likely that once you scroll to what it thinks is the end, there are more items, its size estimate changes and now the list is bigger than before. This seems to keep repeating. Without knowing the size of all the groups (which is what the outer repeater is trying to do), this is hard to solve. If all the groups are the same size, I suspect it works better. This does make for a weird experience when dragging the mouse thumb.

christosk92 commented 7 months ago

@christosk92 the outer repeater does not know the extent. It is making estimates on what it could be depending on the size of the groups it has seen so far and the number of groups. If the groups are of widely varying sizes, then it is likely that once you scroll to what it thinks is the end, there are more items, its size estimate changes and now the list is bigger than before. This seems to keep repeating. Without knowing the size of all the groups (which is what the outer repeater is trying to do), this is hard to solve. If all the groups are the same size, I suspect it works better. This does make for a weird experience when dragging the mouse thumb.

That makes a lot of sense, thanks for the clarification.

For my case: An album can have a random number of tracks (1, 5,10,12,40 etc and anything in between). I can make an estimation on the number of tracks an album will have (Albums usually have 10, singles 2) but the actual number can change once the album is fetched.

Do you have any clue whatsoever as to how I can approach this problem? Do you think writing my own layout can remedy this? Another option could be to fetch all the album first and then calculate the size based on the number of tracks.... But that is slow and would require a blocking action for the user which is less than ideal...

christosk92 commented 7 months ago

Well another thing I could do is just say like: 1) Albums have est. 10 tracks 2) Singles have est. 2 tracks

There is some lazy loading where items get fetched only if they are in the viewport for longer than ~300 ms(?). This way scrolling never results in unexpected size shifts since the height is already pre-computed. Thoughts on this?

ranjeshj commented 7 months ago

@christosk92 These are the challenges with virtualized layouts that operate with not enough information. If you can get accurate sizes based on the count of items, writing a custom layout outer layout will definitely get you a better experience. It should be possible to measure each child that is in the viewport and use the counts/sizes to accurately represent the items outside the viewport. As long as the numbers you come up with don't change as you scroll, you should get accurate thumb behavior.

yaira2 commented 4 months ago

A user reported this issue in Files as well https://github.com/files-community/Files/issues/15158.

christosk92 commented 4 months ago

@christosk92 These are the challenges with virtualized layouts that operate with not enough information. If you can get accurate sizes based on the count of items, writing a custom layout outer layout will definitely get you a better experience. It should be possible to measure each child that is in the viewport and use the counts/sizes to accurately represent the items outside the viewport. As long as the numbers you come up with don't change as you scroll, you should get accurate thumb behavior.

I get that but with modern data sets (which are probably paged), the result of an API call is unknown, it may be higher or lower than previous items. The scrolling examples in the sample app etc work fine with the most trivial, offline and local datasets that never change. But once you start building real web-connected apps it all changes.

I have never experienced such a thing on mobile apps, or even web apps. Why isn't this a thing that is being considered? Variable datasets are highly common in a lot of applications.