From 2949491eb437b5c7305f548c281b70ece3323dba Mon Sep 17 00:00:00 2001 From: NanthiniMahalingam <105482474+NanthiniMahalingam@users.noreply.github.com> Date: Mon, 15 Dec 2025 13:00:34 +0530 Subject: [PATCH 1/3] Fixed the header issue on first measure item. --- .../Handlers/Items2/iOS/TemplatedCell2.cs | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs index 7136d9e1c1b6..fe0e3bbe8609 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs @@ -107,20 +107,30 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin if (_measureInvalidated || _cachedConstraints != constraints) { - // Check if we should use the cached first item size for MeasureFirstItem optimization - var cachedSize = GetCachedFirstItemSizeFromHandler(); - if (cachedSize != CGSize.Empty) + // Only use the cached first-item measurement for actual item cells (not headers/footers) + // Supplementary views (headers/footers) set the flag `isHeaderOrFooterChanged` during Bind + // so we can detect them here and avoid using the item cache for their measurement. + if (isHeaderOrFooterChanged) { - _measuredSize = cachedSize.ToSize(); - // Even when we have a cached measurement, we still need to call Measure - // to update the virtual view's internal state and bookkeeping - virtualView.Measure(constraints.Width, _measuredSize.Height); + var cachedSize = GetCachedFirstItemSizeFromHandler(); + if (cachedSize != CGSize.Empty) + { + _measuredSize = cachedSize.ToSize(); + // Even when we have a cached measurement, we still need to call Measure + // to update the virtual view's internal state and bookkeeping + virtualView.Measure(constraints.Width, _measuredSize.Height); + } + else + { + _measuredSize = virtualView.Measure(constraints.Width, constraints.Height); + // If this is the first item being measured, cache it for MeasureFirstItem strategy + SetCachedFirstItemSizeToHandler(_measuredSize.ToCGSize()); + } } else { + // For headers/footers, always measure directly without using or updating the first-item cache _measuredSize = virtualView.Measure(constraints.Width, constraints.Height); - // If this is the first item being measured, cache it for MeasureFirstItem strategy - SetCachedFirstItemSizeToHandler(_measuredSize.ToCGSize()); } _cachedConstraints = constraints; _needsArrange = true; From 4108f297fc31beaf441ef8eb65c9cbb87c4d17e3 Mon Sep 17 00:00:00 2001 From: NanthiniMahalingam <105482474+NanthiniMahalingam@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:08:45 +0530 Subject: [PATCH 2/3] Updated the fix --- .../Handlers/Items2/iOS/GroupableItemsViewController2.cs | 2 ++ .../src/Core/Handlers/Items2/iOS/ItemsViewController2.cs | 2 ++ .../Handlers/Items2/iOS/StructuredItemsViewController2.cs | 1 + src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs | 5 ++++- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/GroupableItemsViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/GroupableItemsViewController2.cs index 0c3be0ff8e71..ff0b7c98dda9 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/GroupableItemsViewController2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/GroupableItemsViewController2.cs @@ -127,6 +127,8 @@ void UpdateTemplatedSupplementaryView(TemplatedCell2 cell, NSString elementKind, var bindingContext = ItemsSource.Group(indexPath); + // Mark this templated cell as a supplementary view (header/footer) + cell.isSupplementaryView = true; cell.isHeaderOrFooterChanged = true; cell.Bind(template, bindingContext, ItemsView); cell.isHeaderOrFooterChanged = false; diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs index f9af7cc33fab..a1c239ef4240 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs @@ -119,6 +119,8 @@ public override UICollectionViewCell GetCell(UICollectionView collectionView, NS { TemplatedCell2.ScrollDirection = ScrollDirection; + // Ensure this cell is treated as a regular item cell (not a supplementary view) + TemplatedCell2.isSupplementaryView = false; TemplatedCell2.Bind(ItemsView.ItemTemplate, ItemsSource[indexpathAdjusted], ItemsView); } else if (cell is DefaultCell2 DefaultCell2) diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/StructuredItemsViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/StructuredItemsViewController2.cs index 87413f640e97..ec01d92cd6d0 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/StructuredItemsViewController2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/StructuredItemsViewController2.cs @@ -130,6 +130,7 @@ void UpdateTemplatedSupplementaryView(TemplatedCell2 cell, NSString elementKind) { bool isHeader = elementKind == UICollectionElementKindSectionKey.Header; cell.isHeaderOrFooterChanged = true; + cell.isSupplementaryView = true; if (isHeader) { diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs index fe0e3bbe8609..59f150407bbc 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs @@ -40,6 +40,8 @@ public event EventHandler LayoutAttributesCha Size _measuredSize; Size _cachedConstraints; + // Indicates the cell is being used as a supplementary view (group header/footer) + internal bool isSupplementaryView = false; internal bool MeasureInvalidated => _measureInvalidated; // Flags changes confined to the header/footer, preventing unnecessary recycling and revalidation of templated cells. @@ -110,7 +112,7 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin // Only use the cached first-item measurement for actual item cells (not headers/footers) // Supplementary views (headers/footers) set the flag `isHeaderOrFooterChanged` during Bind // so we can detect them here and avoid using the item cache for their measurement. - if (isHeaderOrFooterChanged) + if (!isSupplementaryView) { var cachedSize = GetCachedFirstItemSizeFromHandler(); if (cachedSize != CGSize.Empty) @@ -204,6 +206,7 @@ public override void LayoutSubviews() public override void PrepareForReuse() { //Unbind(); + isSupplementaryView = false; base.PrepareForReuse(); } From c0a22c51b319e90578ba433038d7569f02b4714a Mon Sep 17 00:00:00 2001 From: NanthiniMahalingam <105482474+NanthiniMahalingam@users.noreply.github.com> Date: Mon, 15 Dec 2025 18:15:04 +0530 Subject: [PATCH 3/3] Added the test case --- .../Handlers/Items2/iOS/TemplatedCell2.cs | 2 - .../TestCases.HostApp/Issues/Issue33130.xaml | 71 +++++++++++++++++++ .../Issues/Issue33130.xaml.cs | 66 +++++++++++++++++ .../Tests/Issues/Issue33130.cs | 44 ++++++++++++ 4 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue33130.xaml create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue33130.xaml.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33130.cs diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs index 59f150407bbc..1e7f74e7a807 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs @@ -110,8 +110,6 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin if (_measureInvalidated || _cachedConstraints != constraints) { // Only use the cached first-item measurement for actual item cells (not headers/footers) - // Supplementary views (headers/footers) set the flag `isHeaderOrFooterChanged` during Bind - // so we can detect them here and avoid using the item cache for their measurement. if (!isSupplementaryView) { var cachedSize = GetCachedFirstItemSizeFromHandler(); diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue33130.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue33130.xaml new file mode 100644 index 000000000000..4f2d924fac6e --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue33130.xaml @@ -0,0 +1,71 @@ + + + + +