maui
maui copied to clipboard
Grouped CollectionView content/items overlaps on iOS when data changes or when pull to refresh data
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
-
Create a new MAUI app project using usual VS for Mac
-
Create ObservableCollection for grouped data:
-
[ObservableProperty] ObservableCollection<IGrouping<DateTime?, Items>> groupedItems;
-
Populate the data from API or your data model
-
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>
-
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.
-
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
-
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 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.
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 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.
@jsuarezruiz I'm using the latest MAUI version for both android and iOS and this issue still persists.
@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();
}
}
@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.
@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.
@jsuarezruiz , this appears to still be an issue in the latest release of Maui 8.0.7 (as of today).
I can confirm seeing this issue only on iOS (Android and Windows are fine) on 8.0.7
Still there's no fix or discussion to fix this issue by anyone. That's quite disappointing!
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.
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.
@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.
@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.
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
@rrelyea can you add me to the repo ? @nsood9 are you able to reproduce this with file new maui app ?
@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.
@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.
@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"?
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.
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....
@filipleifer Facing the same issue for the iOS Platform @rrelyea @Uridel
@nsood9 i am also facing same issue. did you fixed this issue?
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:
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.
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();
}
}
}