Skip to content
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

Grouped CollectionView content/items overlaps on iOS when data changes or when pull to refresh data #20336

Closed
nsood9 opened this issue Feb 2, 2024 · 25 comments · Fixed by #24873
Assignees
Labels
Milestone

Comments

@nsood9
Copy link

nsood9 commented Feb 2, 2024

Description

On iOS when CollectionView is used to display grouped data, the content items displayed in the CollectionView overlaps. For the first time it calculates the size correctly and shows everything as expected, but if sometimes, the list data changes or I pull to refresh new data (using RefreshView), the collection content is overlapping and looks so ugly.

Steps to Reproduce

  1. Create a new MAUI app project using usual VS for Mac

  2. Create ObservableCollection for grouped data:

  3. [ObservableProperty]
    ObservableCollection<IGrouping<DateTime?, Items>> groupedItems;

  4. Populate the data from API or your data model

  5. Design your layout to include CollectionView with DataTemplateSelector:

<ResourceDictionary>
<templateSelector:ItemDataTemplateSelector x:Key="itemDataTemplateSelector"
                                        TemplateOne ="{StaticResource DataTemplateOne}"
                                        TemplateTwo ="{StaticResource DataTemplateTwo}"
                                       TemplateThree ="{StaticResource DataTemplateThree}"
                                        TemplateFour ="{StaticResource DataTemplateFour}"
                                        TemplateFive ="{StaticResource DataTemplateFive}"/>

      </ResourceDictionary>
      
      
      <RefreshView Grid.Row="0"  VerticalOptions="FillAndExpand" IsRefreshing="{Binding IsRefreshing}"
                   RefreshColor="{StaticResource Primary}"
                   Command="{Binding RefreshCommand}">
      <CollectionView TranslationY="-23"
          VerticalScrollBarVisibility="Always" ItemTemplate="{StaticResource itemDataTemplateSelector}"
          ItemsSource="{Binding GroupedItems}"  VerticalOptions="FillAndExpand"
          IsGrouped="True" ItemsUpdatingScrollMode="KeepLastItemInView">
          <CollectionView.ItemsLayout>
              <GridItemsLayout VerticalItemSpacing="5"
                  Orientation="Vertical" />
          </CollectionView.ItemsLayout>
          <CollectionView.GroupHeaderTemplate>
              <DataTemplate>
                  <Label Style="{StaticResource HeadingTextStyle}"
                      Padding="30,10,30,0" 
                      Text="{Binding Key, StringFormat='{0: dddd, MMMM dd}'}"
                      VerticalTextAlignment="Center" 
                       />
              </DataTemplate>
          </CollectionView.GroupHeaderTemplate>
          </CollectionView>
          </RefreshView>
  1. Run in iOS simulator, it will look good the very first time and then if you pull to refresh the data, observe the bad overlapping.

  2. Data is dynamic, it will sometimes overlap if the data is changed during runtime and some of the data templates are now not available as per the data

  3. I cannot use ItemSizingStrategy="MeasureFirstItem" because, my design list design requires different data templates, which are of complete different sizes, so there is no chance I can use MeasureFirstItem ItemSizingStrategy.

Due to this, the UI for the very first screen of my app looks so bad that it's not possible to release or at least demo it to client.

Link to public reproduction project repository

No response

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+

Did you find any workaround?

Couldn't find any workaround yet.

Relevant log output

No response

@nsood9 nsood9 added the t/bug Something isn't working label Feb 2, 2024
@jsuarezruiz jsuarezruiz added the area-controls-collectionview CollectionView, CarouselView, IndicatorView label Feb 5, 2024
@borrmann
Copy link
Contributor

borrmann commented Feb 5, 2024

@nsood9 I have seen a samilar issue. In my case the Group Headers wouldnt be removed when I clear my ItemsSource, then causing overlaps between old group headers and the new items/ headers.
As a workaround you can group your data yourself, and add another Object to your list for each Group with their own Template. If you cant use the same type for your header you can use a composition class with your object type and your group header type.

@jsuarezruiz jsuarezruiz added the s/try-latest-version Please try to reproduce the potential issue on the latest public version label Feb 5, 2024
@ghost
Copy link

ghost commented Feb 5, 2024

Hi @nsood9. We have added the "s/try-latest-version" label to this issue, which indicates that we'd like you to try and reproduce this issue on the latest available public version. This can happen because we think that this issue was fixed in a version that has just been released, or the information provided by you indicates that you might be working with an older version.

You can install the latest version by installing the latest Visual Studio (Preview) with the .NET MAUI workload installed. If the issue still persists, please let us know with any additional details and ideally a reproduction project provided through a GitHub repository.

This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

@nsood9
Copy link
Author

nsood9 commented Feb 5, 2024

@nsood9 I have seen a samilar issue. In my case the Group Headers wouldnt be removed when I clear my ItemsSource, then causing overlaps between old group headers and the new items/ headers. As a workaround you can group your data yourself, and add another Object to your list for each Group with their own Template. If you cant use the same type for your header you can use a composition class with your object type and your group header type.

I'm also facing the exact same issue apart from the one I've created a bug for. The group headers are not removing even when the ItemSource is null or I clear it manually, the group headers are always sticking to the view no matter what and then overlaps with the new/actual header and items. I didn't understand the way you've suggested to handle this case. Can you please explain it with an example, because my data structure is: I have 3-4 types of data to show in the CollectionView using DataTemplateSelector based on their types and a DateTime property is the grouping factor based on which I've grouped the collection and displaying them as group of items under different Dates as header.

@ghost ghost removed the s/try-latest-version Please try to reproduce the potential issue on the latest public version label Feb 5, 2024
@nsood9
Copy link
Author

nsood9 commented Feb 5, 2024

@jsuarezruiz I'm using the latest MAUI version for both android and iOS and this issue still persists.

@borrmann
Copy link
Contributor

borrmann commented Feb 5, 2024

@nsood9

Something like this:

 public class TestTemplateSelector : DataTemplateSelector
 {
     public DataTemplate Test1 { get; set; }
     public DataTemplate Test2 { get; set; }
     public DataTemplate Test3 { get; set; }
     public DataTemplate Header { get; set; }

     protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
     {
         var ts = (Composition)item;

         if (ts.Header != null)
         {
             return Header;

         }
         else if (ts.ObjectClass.Test == ObjectClass.TestEnum.Test1)
         {
             return Test1;
         }
         else if (ts.ObjectClass.Test == ObjectClass.TestEnum.Test2)
         {
             return Test2;
         }
         else if (ts.ObjectClass.Test == ObjectClass.TestEnum.Test3)
         {
             return Test3;
         }   
     }
 }


 public class ObjectClass
 {
     public enum TestEnum
     {
         Test1,
         Test2,
         Test3
     } 
     public TestEnum Test { get; init; }
 }

 public class HeaderClass
 {
     public string Header { get; init; }  
 }

 public class Composition
 {
     public ObjectClass.TestEnum Key { get; init; }
     public HeaderClass Header { get; init; }
     public HeaderClass ObjectClass { get; init; }
 }   

 public class C 
 { 

     public void CreateList()
     {
         List<ObjectClass> objectClasses = new List<ObjectClass>()
         {
             new ObjectClass(){ Test = ObjectClass.TestEnum.Test1 },
             new ObjectClass() { Text = ObjectClass.TestEnum.Test2 },
             new ObjectClass() { Text = ObjectClass.TestEnum.Test3 },
         };


         List<Composition> ItemsSourceList = objectClasses.GroupBy(x => x.Test).Select(x => new Composition()
         {
             Key = x.Key
             Header = new HeaderClass() { Header = x.Key.ToString() },
             ObjectClass = null
         }).ToList().Concat(objectClasses.Select(x=>new Composition() { HeaderClass = null, ObjectClass = x, Key = x.Key } )).OrderBy(x => x.Key).ThenBy(x=>x.Header != null).ToList();    

     }
 }

@nsood9
Copy link
Author

nsood9 commented Feb 6, 2024

@borrmann Thank you for sharing the logic, I need to give it a try with the type of data and UI requirement I have in my project. But instead of any workaround, is there any fix available for the existing Grouped CollectionView overlapping issue? MAUI team should fix this issue as it a major UI bug faced by number of people working with MAUI, but it is a very basic requirement of any app to be able to display grouped collection data without any cosmetic problems.

@nsood9
Copy link
Author

nsood9 commented Feb 12, 2024

@jamesmontemagno @jonathanpeppers Are we planning to fix this overlapping issue for Grouped Collectionview in the upcoming release as this is a very basic requirement for any app to be able to use a grouped CollectionView to show grouped data. At this point the list in my app is not that big, it just contains 5-10 records at a time, still the UI looks so bad because of this overlapping issue, every text and cell just overlaps on each other. But as the user base grows, the data/records will also grow and I wonder how disastrous a simple grouped CollectionView UI will look then. Can we please prioritize this issue for the upcoming release as it's a basic UI control and working with MAUI for an app, one should be able to use at least the basic controls without these UI bugs.

@UnusualJustin
Copy link

@jsuarezruiz , this appears to still be an issue in the latest release of Maui 8.0.7 (as of today).

@bmacombe
Copy link
Contributor

I can confirm seeing this issue only on iOS (Android and Windows are fine) on 8.0.7

@nsood9
Copy link
Author

nsood9 commented Feb 28, 2024

Still there's no fix or discussion to fix this issue by anyone. That's quite disappointing!

@rrelyea
Copy link

rrelyea commented Mar 1, 2024

Blocking me. I'm seeing this on the iOS version of my net Maui app. Grouped collectionview inside refreshview. Happens in about half of my scenarios when user chooses to refresh. I've found no workaround (no way to reset the collectionview, other than recreating the element.)
My repo is private, but I'd happily give permissions to the dev working on a fix, if you need a repro.

@Uridel
Copy link

Uridel commented Mar 12, 2024

We are also suffering massively from this issue. It is causing a delay in releasing our software. Is there a workaround or has this been prioritized. Grouped collections are a basic function in my opinion.

@borrmann
Copy link
Contributor

@Uridel I have posted a workaround above. I am using that everywhere where I need Grouped Collections and it works fine.
I also don't see performance issues at all. Sure, it adds a bit more complexity but if you need to release your software it might be worth giving it a try.

@Uridel
Copy link

Uridel commented Mar 12, 2024

@borrmann It isn't really a viable options as our application is rather large. It would mean changing ~100 Grouped collectionviews. Some of which have varying complexities of the way I view data. While I commend you for the solution, i also wonder what the impact on performance will be. Nevertheless this is an issue the Maui teams must fix.

@PureWeen PureWeen added the s/needs-repro Attach a solution or code which reproduces the issue label Mar 12, 2024
@rmarinho
Copy link
Member

Blocking me. I'm seeing this on the iOS version of my net Maui app. Grouped collectionview inside refreshview. Happens in about half of my scenarios when user chooses to refresh. I've found no workaround (no way to reset the collectionview, other than recreating the element.) My repo is private, but I'd happily give permissions to the dev working on a fix, if you need a repro.

Hey Rob .. wonder if you can add me to the repo so I can take a look. Thanks

@dotnet-policy-service dotnet-policy-service bot added the s/no-recent-activity Issue has had no recent activity label Mar 19, 2024
@rmarinho rmarinho self-assigned this Mar 19, 2024
@dotnet-policy-service dotnet-policy-service bot removed the s/no-recent-activity Issue has had no recent activity label Mar 19, 2024
@rmarinho
Copy link
Member

@rrelyea can you add me to the repo ? @nsood9 are you able to reproduce this with file new maui app ?

@UnusualJustin
Copy link

@rmarinho , I could not recreate this issue today no matter what I tried. If I do find a scenario that triggers it, I'll create a sample repo and tag you.

@dotnet-policy-service dotnet-policy-service bot added s/needs-attention Issue has more information and needs another look and removed s/needs-repro Attach a solution or code which reproduces the issue labels Mar 19, 2024
@rrelyea
Copy link

rrelyea commented Mar 19, 2024

@rrelyea can you add me to the repo ?

Sorry for the delay. Thanks for looking.

You have been invited to https://github.com/bogle-tools/retiremaze now.
Need to clone bogle-tools/site and /retiremaze enlistments (retiremaze uses a DLL that is only built in /site.
Run it on iOS. Press "test tube" on profiles page to create sample data.
To make refresh take normal time...sign up for apikey from eodhd.com and enter that on settings page.

Tab 2, 4, and 5 are the ones that used grouped collectionviews. tab 5 is the one that shows the problem (duplicated/dead headers when scrolling and/or doing a refresh operation.
Those 3 tabs show very slow scrolling too!

Tab 3 is using a fake grouping...not collectionview grouping.
I'm reproing on my iPhone 11 Pro.

Update: related/different issue; the refresh view also scrolls content down a bit instead of staying at the top.

@nsood9
Copy link
Author

nsood9 commented Mar 19, 2024

@rrelyea can you add me to the repo ? @nsood9 are you able to reproduce this with file new maui app ?

Sorry, I didn't get it. I'm using the latest MAUI version for my app and still facing this issue. The grouped collection view does gets distorted on iOS, specially if we use pull to refresh view and user pulls to refresh data, all of the cells/records and their group headings overlap each other. And even when the data is being loaded the empty list keep displaying the old group headings which it shouldn't display.

I didn't get what do you mean by "file new maui app"?

@rutgersc
Copy link

rutgersc commented Mar 28, 2024

Running into similar problems after applying workarounds (this and this one) for crashes on iOS: #10163, #18481, #20037.

Haven't yet come across a workaround that consistently works for these invalid sized/overlapping items. Honestly, I can't believe how some of the most basic UI components (both listview and collectionview) are so broken beyond repair.

Really hope someone is able to pinpoint where these issues come from.

@filipleifer
Copy link

We have same problem. Different item hights in grouped CollectionView on iOS makes overlapping group headers over items. We are forced to use fixed heights. Really bad....

@vplife1
Copy link

vplife1 commented May 7, 2024

@filipleifer Facing the same issue for the
iOS Platform @rrelyea @Uridel

@Sky202394
Copy link

@nsood9 i am also facing same issue. did you fixed this issue?

@jsuarezruiz jsuarezruiz added this to the Backlog milestone Jun 6, 2024
@jsuarezruiz jsuarezruiz removed the s/needs-attention Issue has more information and needs another look label Jun 6, 2024
@YARG
Copy link

YARG commented Jun 18, 2024

The overlap issue I had with the CollectionView on iOS is that when initially populated it was fine but when I applied a filter, scrolled down the list and then removed the filter I would see an overlap, as in the screenshot below:

Screenshot 2024-06-18 at 06 33 52

The fix, for me at least, was to scroll to the top of the CollectionView first in code and then update the CollectionView.

YouCollectionView.ScrollTo(0, position: ScrollToPosition.Start, animate: false)

I'm using MVVM, so I had to send a message from the ViewModel (via WeakReferenceMessenger) which the View(Page) picked up.

To test, manually scroll to the start of the list and make your changes to see if that fix will work for you.

I hope this helps.

@espenrl
Copy link
Contributor

espenrl commented Jun 21, 2024

I've solved the problem with this code

handlers.AddHandler<CollectionView, CollectionViewHandlerEx>();
CollectionViewHandler.Mapper.ModifyMapping(nameof(CollectionView.ItemsSource), MapItemsSource);

private static void MapItemsSource(CollectionViewHandler handler, CollectionView view, Action<IElementHandler, IElement>? existingMapper)
{
    // ISSUE: for grouped CollectionView, content overlaps after changes to ItemsSource or collection
    // https://github.com/dotnet/maui/issues/20336
    if (view.IsGrouped && handler.PlatformView.Subviews is [UICollectionView collectionView])
    {
        collectionView.ClearSubviews();
    }

    var oldItemsSource = view.ItemsSource;

    // run existing mapper
    if (existingMapper is not null)
    {
        existingMapper(handler, view);
    }

    var newItemsSource = view.ItemsSource;

    // listen to collection changes and run fix when collection is reset
    if (handler is not CollectionViewHandlerEx collectionViewHandler)
    {
        return;
    }

    if (oldItemsSource is INotifyCollectionChanged oldNotifyCollectionChanged)
    {
        oldNotifyCollectionChanged.CollectionChanged -= collectionViewHandler.NotifyCollectionChanged_CollectionChanged;
    }

    if (newItemsSource is INotifyCollectionChanged newNotifyCollectionChanged)
    {
        newNotifyCollectionChanged.CollectionChanged += collectionViewHandler.NotifyCollectionChanged_CollectionChanged;
    }
}

internal sealed class CollectionViewHandlerEx : CollectionViewHandler
{
    internal void NotifyCollectionChanged_CollectionChanged(object? _, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action is not NotifyCollectionChangedAction.Reset)
        {
            return;
        }

        // ISSUE: for grouped CollectionView, content overlaps after changes to ItemsSource or collection
        // https://github.com/dotnet/maui/issues/20336
        if (VirtualView is CollectionView { IsGrouped: true } && PlatformView.Subviews is [UICollectionView collectionView])
        {
            collectionView.ClearSubviews();
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment