diff --git a/src/Controls/src/Core/Handlers/Items/Android/Adapters/AdapterNotifier.cs b/src/Controls/src/Core/Handlers/Items/Android/Adapters/AdapterNotifier.cs
index 6ed445bd5e3e..192d10afbb4e 100644
--- a/src/Controls/src/Core/Handlers/Items/Android/Adapters/AdapterNotifier.cs
+++ b/src/Controls/src/Core/Handlers/Items/Android/Adapters/AdapterNotifier.cs
@@ -29,9 +29,6 @@ public void NotifyItemInserted(IItemsViewSource source, int startIndex)
if (IsValidAdapter())
{
_adapter.NotifyItemInserted(startIndex);
-
- var changedCount = _adapter.ItemCount - startIndex;
- _adapter.NotifyItemRangeChanged(startIndex, changedCount);
}
}
@@ -40,10 +37,6 @@ public void NotifyItemMoved(IItemsViewSource source, int fromPosition, int toPos
if (IsValidAdapter())
{
_adapter.NotifyItemMoved(fromPosition, toPosition);
-
- var minPosition = System.Math.Min(fromPosition, toPosition);
- var changedCount = _adapter.ItemCount - minPosition;
- _adapter.NotifyItemRangeChanged(minPosition, changedCount);
}
}
@@ -58,9 +51,6 @@ public void NotifyItemRangeInserted(IItemsViewSource source, int startIndex, int
if (IsValidAdapter())
{
_adapter.NotifyItemRangeInserted(startIndex, count);
-
- var changedCount = _adapter.ItemCount - startIndex;
- _adapter.NotifyItemRangeChanged(startIndex, changedCount);
}
}
@@ -69,9 +59,6 @@ public void NotifyItemRangeRemoved(IItemsViewSource source, int startIndex, int
if (IsValidAdapter())
{
_adapter.NotifyItemRangeRemoved(startIndex, count);
-
- var changedCount = _adapter.ItemCount - startIndex;
- _adapter.NotifyItemRangeChanged(startIndex, changedCount);
}
}
@@ -80,9 +67,6 @@ public void NotifyItemRemoved(IItemsViewSource source, int startIndex)
if (IsValidAdapter())
{
_adapter.NotifyItemRemoved(startIndex);
-
- var changedCount = _adapter.ItemCount - startIndex;
- _adapter.NotifyItemRangeChanged(startIndex, changedCount);
}
}
diff --git a/src/Controls/src/Core/Handlers/Items/Android/MauiRecyclerView.cs b/src/Controls/src/Core/Handlers/Items/Android/MauiRecyclerView.cs
index c4afc301aa67..9bcc1758eb3e 100644
--- a/src/Controls/src/Core/Handlers/Items/Android/MauiRecyclerView.cs
+++ b/src/Controls/src/Core/Handlers/Items/Android/MauiRecyclerView.cs
@@ -567,11 +567,12 @@ internal void UpdateEmptyViewVisibility()
itemCount++;
}
- var showEmptyView = ItemsView?.EmptyView != null && ItemsViewAdapter.ItemCount == itemCount;
+ var showEmptyView = (ItemsView?.EmptyView is not null || ItemsView?.EmptyViewTemplate is not null) && ItemsViewAdapter.ItemCount == itemCount;
var currentAdapter = GetAdapter();
if (showEmptyView && currentAdapter != _emptyViewAdapter)
{
+ GetRecycledViewPool().Clear();
SwapAdapter(_emptyViewAdapter, true);
// TODO hartez 2018/10/24 17:34:36 If this works, cache this layout manager as _emptyLayoutManager
@@ -580,6 +581,7 @@ internal void UpdateEmptyViewVisibility()
}
else if (!showEmptyView && currentAdapter != ItemsViewAdapter)
{
+ GetRecycledViewPool().Clear();
SwapAdapter(ItemsViewAdapter, true);
UpdateLayoutManager();
}
diff --git a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs
index 3e10fd5c2544..6d0feb80116a 100644
--- a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs
+++ b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs
@@ -567,7 +567,7 @@ protected virtual void HandleFormsElementMeasureInvalidated(VisualElement formsE
internal void UpdateView(object view, DataTemplate viewTemplate, ref UIView uiView, ref VisualElement formsElement)
{
// Is view set on the ItemsView?
- if (view == null)
+ if (view is null && viewTemplate is null)
{
if (formsElement != null)
{
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/CollectionViewHeaderBlankWhenLastItemRemoved.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/CollectionViewHeaderBlankWhenLastItemRemoved.png
new file mode 100644
index 000000000000..f537c8555dd0
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/CollectionViewHeaderBlankWhenLastItemRemoved.png differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png
new file mode 100644
index 000000000000..e543f83433c2
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png differ
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml
new file mode 100644
index 000000000000..7de4c4225914
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml.cs
new file mode 100644
index 000000000000..6a37a19ae6de
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using System.Windows.Input;
+using System.Collections.Specialized;
+
+
+namespace Maui.Controls.Sample.Issues
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ [Issue(IssueTracker.Github, 11896, "CollectionView Header/Footer/EmptyView issues when adding/removing items", PlatformAffected.Android)]
+ public partial class Issue11896
+ {
+ public Issue11896()
+ {
+ InitializeComponent();
+ BindingContext = new Issue11896ViewModel();
+ }
+ }
+ internal class Issue11896ViewModel
+ {
+ // Define a static list of cities to add to the collection
+ private List _staticCities = new()
+ {
+ "Paris",
+ "New York",
+ "Tokyo",
+ "Berlin",
+ "Madrid",
+ "London"
+ };
+
+ private int _currentIndex = 0;
+
+ public ObservableCollection ItemList { get; set; }
+
+ public ICommand AddCommand => new Command(Add);
+ public ICommand RemoveCommand => new Command(Remove);
+
+ public Issue11896ViewModel()
+ {
+ // Initialize the ItemList
+ ItemList = new ObservableCollection();
+ }
+
+ private void Add()
+ {
+ // Add the next city from the static list
+ if (_currentIndex < _staticCities.Count)
+ {
+ ItemList.Add(_staticCities[_currentIndex]);
+ _currentIndex++;
+ }
+ else
+ {
+ // Optionally reset the index or handle the end of the list as needed
+ _currentIndex = 0; // Resetting to allow cycling through the list again
+ }
+ }
+
+ private void Remove()
+ {
+ // Remove the last item in the list if any exist
+ if (ItemList.Count > 0)
+ {
+ ItemList.RemoveAt(ItemList.Count - 1);
+ // Decrement the index to ensure the correct city is added next time
+ _currentIndex = Math.Max(0, _currentIndex - 1);
+ }
+ }
+ }
+}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue11896.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue11896.cs
new file mode 100644
index 000000000000..a057489b7ddf
--- /dev/null
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue11896.cs
@@ -0,0 +1,41 @@
+#if !MACCATALYST && !WINDOWS
+using NUnit.Framework;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.TestCases.Tests.Issues
+{
+ internal class Issue11896 : _IssuesUITest
+ {
+ public Issue11896(TestDevice device) : base(device) { }
+
+ public override string Issue => "CollectionView Header/Footer/EmptyView issues when adding/removing items";
+
+ [Test]
+
+ [Category(UITestCategories.CollectionView)]
+ public void CollectionviewFooterHideswhenDynamicallyAddorRemoveItems()
+ {
+ App.WaitForElement("AddButton");
+ App.Tap("AddButton");
+ App.Tap("AddButton");
+ App.Tap("AddButton");
+ // Here we check for Footer proper visibility with proper alignment in view.
+ VerifyScreenshot();
+ }
+
+ [Test]
+ [Category(UITestCategories.CollectionView)]
+ public void CollectionViewHeaderBlankWhenLastItemRemoved()
+ {
+ App.WaitForElement("AddButton");
+ App.Tap("RemoveButton");
+ App.Tap("RemoveButton");
+ App.Tap("RemoveButton");
+ App.Tap("AddButton");
+ // Here we check for Header and Footer proper visibility with proper alignment in view.
+ VerifyScreenshot();
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewHeaderBlankWhenLastItemRemoved.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewHeaderBlankWhenLastItemRemoved.png
new file mode 100644
index 000000000000..22cd5a3557ad
Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewHeaderBlankWhenLastItemRemoved.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png
new file mode 100644
index 000000000000..7856bad80188
Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png differ