Skip to content

Commit

Permalink
[ios,tests] Fix iOS Header with Group (#25157)
Browse files Browse the repository at this point in the history
* [tests] Add CV header/footer tests

* Update more tests

* Fixes

* [iOS] Make sure to distinguish between group header and global header on CV2

* [iOS] Porting fix #24830

* [tests] Add test for issue 20443

* [testing] run these tests on iOS for now

Fix build

Add missing usings

* Fix #12429

* Update StructuredItemsViewController.cs

* [iOS] CV2 fix footer

* [iOS] Make sure to handle also the header or footer template

* Fix images

* [tests] This is a bug on CV2

---------

Co-authored-by: Jakub Florkowski <kubaflo123@gmail.com>
  • Loading branch information
rmarinho and kubaflo authored Oct 22, 2024
1 parent 0f79050 commit c511d78
Show file tree
Hide file tree
Showing 17 changed files with 322 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ protected override void Dispose(bool disposing)
_footerViewFormsElement.MeasureInvalidated -= OnFormsElementMeasureInvalidated;
}

if (_headerUIView is MauiView hv)
{
hv.LayoutChanged -= HeaderViewLayoutChanged;
}

if (_footerUIView is MauiView fv)
{
fv.LayoutChanged -= FooterViewLayoutChanged;
}

_headerUIView = null;
_headerViewFormsElement = null;
_footerUIView = null;
Expand Down Expand Up @@ -105,15 +115,26 @@ internal void UpdateFooterView()
UpdateSubview(ItemsView?.Footer, ItemsView?.FooterTemplate, FooterTag,
ref _footerUIView, ref _footerViewFormsElement);
UpdateHeaderFooterPosition();

if (_footerUIView is MauiView mv)
{
mv.LayoutChanged += FooterViewLayoutChanged;
}
}

internal void UpdateHeaderView()
{
UpdateSubview(ItemsView?.Header, ItemsView?.HeaderTemplate, HeaderTag,
ref _headerUIView, ref _headerViewFormsElement);
UpdateHeaderFooterPosition();

if(_headerUIView is MauiView mv)
{
mv.LayoutChanged += HeaderViewLayoutChanged;
}
}


internal void UpdateSubview(object view, DataTemplate viewTemplate, nint viewTag, ref UIView uiView, ref VisualElement formsElement)
{
uiView?.RemoveFromSuperview();
Expand Down Expand Up @@ -239,5 +260,15 @@ internal void UpdateLayoutMeasurements()
if (_footerViewFormsElement != null)
HandleFormsElementMeasureInvalidated(_footerViewFormsElement);
}

void HeaderViewLayoutChanged(object sender, EventArgs e)
{
HandleFormsElementMeasureInvalidated(_headerViewFormsElement);
}

void FooterViewLayoutChanged(object sender, EventArgs e)
{
HandleFormsElementMeasureInvalidated(_footerViewFormsElement);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ protected override UICollectionViewLayout SelectLayout()
{
headerFooterInfo.FooterView = footerView;
}
headerFooterInfo.HasHeader = structuredItemsView.Header is not null;
headerFooterInfo.HasFooter = structuredItemsView.Footer is not null;
headerFooterInfo.HasHeader = structuredItemsView.Header is not null || structuredItemsView.HeaderTemplate is not null;
headerFooterInfo.HasFooter = structuredItemsView.Footer is not null || structuredItemsView.FooterTemplate is not null;
}

var itemSizingStrategy = ItemsView.ItemSizingStrategy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ protected override void RegisterViewTypes()

private protected override void RegisterSupplementaryViews(UICollectionElementKindSection kind)
{
base.RegisterSupplementaryViews(kind);
if (IsHorizontal)
base.RegisterSupplementaryViews(kind);
if (IsHorizontal)
{
CollectionView.RegisterClassForSupplementaryView(typeof(HorizontalSupplementaryView2),
kind, HorizontalSupplementalView2ReuseId);
Expand All @@ -87,10 +87,15 @@ string DetermineViewReuseId(NSString elementKind)
public override UICollectionReusableView GetViewForSupplementaryElement(UICollectionView collectionView,
NSString elementKind, NSIndexPath indexPath)
{
var suplementaryViewFromStructuredView = base.GetViewForSupplementaryElement(collectionView, elementKind, indexPath);
if (suplementaryViewFromStructuredView is not null)
// If the IndexPath is less than 2, it's a header or footer for a section not a group
if (indexPath.Length < 2 || (ItemsView.GroupFooterTemplate is null && ItemsView.GroupHeaderTemplate is null))
{
return suplementaryViewFromStructuredView;

var suplementaryViewFromStructuredView = base.GetViewForSupplementaryElement(collectionView, elementKind, indexPath);
if (suplementaryViewFromStructuredView is not null)
{
return suplementaryViewFromStructuredView;
}
}

var reuseId = DetermineViewReuseId(elementKind);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,14 +401,13 @@ protected virtual CGRect DetermineEmptyViewFrame()
internal void UpdateView(object view, DataTemplate viewTemplate, ref UIView uiView, ref VisualElement formsElement)
{
// Is view set on the ItemsView?
if (view == null)
if (view == null && viewTemplate is null)
{
if (formsElement != null)
{
//Platform.GetRenderer(formsElement)?.DisposeRendererAndChildren();
}


uiView?.Dispose();
uiView = null;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Controls.Sample.UITests;
using Maui.Controls.Sample.CollectionViewGalleries.GroupingGalleries;
using Maui.Controls.Sample.CollectionViewGalleries.HeaderFooterGalleries;
using Maui.Controls.Sample.CollectionViewGalleries.ItemSizeGalleries;
using Maui.Controls.Sample.CollectionViewGalleries.SelectionGalleries;

Expand Down Expand Up @@ -35,6 +37,8 @@ public CollectionViewCoreGalleryContentPage()
// VisitAndUpdateItemsSource (src\Compatibility\ControlGallery\src\UITests.Shared\Tests\CollectionViewUITests.cs)
TestBuilder.NavButton("Default Text Galleries", () => new DefaultTextGallery(), Navigation),
TestBuilder.NavButton("DataTemplate Galleries", () => new DataTemplateGallery(), Navigation),
TestBuilder.NavButton("Grouping Galleries", () => new GroupingGallery(), Navigation),
TestBuilder.NavButton("Header Footer Galleries", () => new HeaderFooterGallery(), Navigation),
TestBuilder.NavButton("Observable Collection Galleries", () => new ObservableCollectionGallery(), Navigation),
// SelectionShouldUpdateBinding (src\Compatibility\ControlGallery\src\Issues.Shared\CollectionViewBoundSingleSelection.cs)
// ItemsFromViewModelShouldBeSelected (src\Compatibility\ControlGallery\src\Issues.Shared\CollectionViewBoundMultiSelection.cs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class HeaderFooterDemoModel : INotifyPropertyChanged

public HeaderFooterDemoModel()
{
CurrentTime = DateTime.Now;
CurrentTime = new DateTime(2023,1,1);
}

void OnPropertyChanged([CallerMemberName] string property = "")
Expand All @@ -36,7 +36,7 @@ void OnPropertyChanged([CallerMemberName] string property = "")

public ObservableCollection<CollectionViewGalleryTestItem> Items => _demoFilteredItemSource.Items;

public ICommand TapCommand => new Command(() => { CurrentTime = DateTime.Now; });
public ICommand TapCommand => new Command(() => { CurrentTime = new DateTime(2024,1,1); });

public DateTime CurrentTime
{
Expand Down
44 changes: 44 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue20443.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Controls.TestCases.HostApp.Issues.Issue20443"
xmlns:local="clr-namespace:Controls.TestCases.HostApp.Issues"
x:DataType="local:Issue20443ViewModel"
Title="Issue20443">
<ContentPage.BindingContext>
<local:Issue20443ViewModel/>
</ContentPage.BindingContext>
<Grid>
<RefreshView
IsRefreshing="{Binding IsRefreshing}"
Command="{Binding RefreshCommand}">
<CollectionView
ItemSizingStrategy="MeasureAllItems"
ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<local:Issue20443TemplateSelector>
<local:Issue20443TemplateSelector.ItemATemplate>
<DataTemplate>
<Grid
HeightRequest="20"
BackgroundColor="Aqua">
<Label Text="20"/>
</Grid>
</DataTemplate>
</local:Issue20443TemplateSelector.ItemATemplate>
<local:Issue20443TemplateSelector.ItemBTemplate>
<DataTemplate>
<Grid
HeightRequest="100"
BackgroundColor="Pink">
<Label Text="100"/>
</Grid>
</DataTemplate>
</local:Issue20443TemplateSelector.ItemBTemplate>
</local:Issue20443TemplateSelector>
</CollectionView.ItemTemplate>

</CollectionView>
</RefreshView>
</Grid>
</ContentPage>
90 changes: 90 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue20443.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;
using System.Runtime.CompilerServices;

namespace Controls.TestCases.HostApp.Issues
{
[Issue(IssueTracker.Github, 20443, "CollectionView item gets wrong size after refresh", PlatformAffected.iOS)]

public partial class Issue20443 : ContentPage
{
public Issue20443()
{
InitializeComponent();
}
}
public class Issue20443ViewModel : INotifyPropertyChanged
{
public IList<object> Items { get; set; }

private bool _isRefreshing;

public bool IsRefreshing
{
get => _isRefreshing;
set
{
_isRefreshing = value;
OnPropertyChanged();
}
}

public Command RefreshCommand { get; set; }

public Issue20443ViewModel()
{
RefreshCommand = new Command(
async () =>
{
await Task.Delay(2000);
IsRefreshing = false;
});

Items = new List<object>();
for (int i = 0; i < 100; i++)
{
Items.Add(new Issue20443ItemA());
Items.Add(new Issue20443ItemB());
Items.Add(new Issue20443ItemB());
Items.Add(new Issue20443ItemB());
Items.Add(new Issue20443ItemB());
}
}

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

public class Issue20443ItemA
{

}

public class Issue20443ItemB
{

}

public class Issue20443TemplateSelector : DataTemplateSelector
{
public DataTemplate ItemATemplate { get; set; }
public DataTemplate ItemBTemplate { get; set; }

protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (item is Issue20443ItemA)
{
return ItemATemplate;
}

return ItemBTemplate;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests
{
#if IOS
public class CollectionViewGroupingTests : CollectionViewUITests
{
protected override bool ResetAfterEachTest => true;

public CollectionViewGroupingTests(TestDevice device)
: base(device)
{
}

[Test]
[Category(UITestCategories.CollectionView)]
public void GroupingAndHeaderWorks()
{
VisitInitialGallery("Grouping");

VisitSubGallery("Basic Grouping");

// header
App.WaitForElement("This is a header");
// group header
App.WaitForElement("Avengers");
// group footer
App.WaitForElement("Total members: 12");
}
}
#endif
}
Loading

0 comments on commit c511d78

Please sign in to comment.