diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/CollectionViewGrouping.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/CollectionViewGrouping.cs
index bf25b99fc42..a56335ba107 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/CollectionViewGrouping.cs
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/CollectionViewGrouping.cs
@@ -29,7 +29,7 @@ protected override void Init()
#endif
}
-#if UITEST && __IOS__ // Grouping is not implemented on Android yet
+#if UITEST
[Test]
public void RemoveSelectedItem()
{
@@ -88,8 +88,6 @@ public void MoveGroup()
RunningApp.WaitForElement("MoveGroup");
RunningApp.Tap("MoveGroup");
}
-
-
#endif
}
}
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7102.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7102.cs
new file mode 100644
index 00000000000..8177ae4b218
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue7102.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+ [Category(UITestCategories.CollectionView)]
+#endif
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Github, 7102, "[Bug] CollectionView Header cause delay to adding items.",
+ PlatformAffected.Android)]
+ public class Issue7102 : TestNavigationPage
+ {
+ protected override void Init()
+ {
+#if APP
+ FlagTestHelpers.SetCollectionViewTestFlag();
+
+ PushAsync(new GalleryPages.CollectionViewGalleries.ObservableCodeCollectionViewGallery(grid: false));
+#endif
+ }
+
+#if UITEST
+ [Test]
+ public void HeaderDoesNotBreakIndexes()
+ {
+ RunningApp.WaitForElement("entryInsert");
+ RunningApp.Tap("entryInsert");
+ RunningApp.ClearText();
+ RunningApp.EnterText("1");
+ RunningApp.Tap("Insert");
+
+ // If the bug is still present, then there will be
+ // two "Item: 0" items instead of the newly inserted item
+ // Or the header will have disappeared
+ RunningApp.WaitForElement("Inserted");
+ RunningApp.WaitForElement("This is the header");
+ }
+#endif
+ }
+}
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
index 998dbbb02aa..1711c8f2c3b 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
@@ -34,6 +34,7 @@
+
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CollectionModifier.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CollectionModifier.cs
index fa81807bfaa..e5b05c789d8 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CollectionModifier.cs
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CollectionModifier.cs
@@ -17,10 +17,10 @@ protected CollectionModifier(CollectionView cv, string buttonText)
HorizontalOptions = LayoutOptions.Fill
};
- var button = new Button { Text = buttonText, AutomationId = $"btn{buttonText}" };
- var label = new Label { Text = LabelText, VerticalTextAlignment = TextAlignment.Center };
+ var button = new Button { Text = buttonText, AutomationId = $"btn{buttonText}", HeightRequest = 20, FontSize = 10 };
+ var label = new Label { Text = LabelText, VerticalTextAlignment = TextAlignment.Center, FontSize = 10 };
- Entry = new Entry { Keyboard = Keyboard.Numeric, Text = InitialEntryText, WidthRequest = 100, AutomationId = $"entry{buttonText}" };
+ Entry = new Entry { Keyboard = Keyboard.Numeric, Text = InitialEntryText, WidthRequest = 100, FontSize = 10, AutomationId = $"entry{buttonText}" };
layout.Children.Add(label);
layout.Children.Add(Entry);
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/BasicGrouping.xaml b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/BasicGrouping.xaml
index 5332e54204b..bc3910b977f 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/BasicGrouping.xaml
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/BasicGrouping.xaml
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGalleries.BasicGrouping">
-
+
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/BasicGrouping.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/BasicGrouping.xaml.cs
index 694b66cdc35..1b03497ae69 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/BasicGrouping.xaml.cs
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/BasicGrouping.xaml.cs
@@ -11,12 +11,12 @@
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGalleries
{
[XamlCompilation(XamlCompilationOptions.Compile)]
- [Preserve (AllMembers = true)]
+ [Preserve(AllMembers = true)]
public partial class BasicGrouping : ContentPage
{
- public BasicGrouping ()
+ public BasicGrouping()
{
- InitializeComponent ();
+ InitializeComponent();
CollectionView.ItemsSource = new SuperTeams();
}
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GridGrouping.xaml b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GridGrouping.xaml
new file mode 100644
index 00000000000..aee06400441
--- /dev/null
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GridGrouping.xaml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GridGrouping.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GridGrouping.xaml.cs
new file mode 100644
index 00000000000..05ea898a068
--- /dev/null
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GridGrouping.xaml.cs
@@ -0,0 +1,14 @@
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGalleries
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class GridGrouping : ContentPage
+ {
+ public GridGrouping()
+ {
+ InitializeComponent();
+ CollectionView.ItemsSource = new SuperTeams();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GroupingGallery.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GroupingGallery.cs
index 00b91423d46..44a34659482 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GroupingGallery.cs
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/GroupingGallery.cs
@@ -32,6 +32,8 @@ public GroupingGallery()
new SwitchGrouping(), Navigation),
GalleryBuilder.NavButton("Grouping, Observable", () =>
new ObservableGrouping(), Navigation),
+ GalleryBuilder.NavButton("Grouping, Grid", () =>
+ new GridGrouping(), Navigation),
}
}
};
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/ObservableGrouping.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/ObservableGrouping.cs
index d97d508898f..3dc6047e290 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/ObservableGrouping.cs
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/ObservableGrouping.cs
@@ -10,7 +10,7 @@ public ObservableGrouping()
Title = "Observable Grouped List";
var buttonStyle = new Style(typeof(Button)) { };
- buttonStyle.Setters.Add(new Setter() { Property = Button.HeightRequestProperty, Value = 20 });
+ buttonStyle.Setters.Add(new Setter() { Property = Button.HeightRequestProperty, Value = 30 });
buttonStyle.Setters.Add(new Setter() { Property = Button.FontSizeProperty, Value = 10 });
var layout = new Grid
@@ -34,6 +34,8 @@ public ObservableGrouping()
var collectionView = new CollectionView
{
+ Header = "This is a header",
+ Footer = "Hey, I'm a footer. Look at me!",
ItemTemplate = ItemTemplate(),
GroupFooterTemplate = GroupFooterTemplate(),
GroupHeaderTemplate = GroupHeaderTemplate(),
@@ -102,7 +104,15 @@ public ObservableGrouping()
Style = buttonStyle };
groupRemover.Clicked += (obj, args) => {
itemsSource?.Remove(itemsSource[0]);
- groupRemover.Text = $"Remove {itemsSource[0].Name}";
+ if (itemsSource.Count > 0)
+ {
+ groupRemover.Text = $"Remove {itemsSource[0].Name}";
+ }
+ else
+ {
+ groupRemover.Text = "";
+ groupRemover.IsEnabled = false;
+ }
mover.Text = $"Move Selected To {itemsSource[0].Name}";
};
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/FooterOnlyString.xaml b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/FooterOnlyString.xaml
new file mode 100644
index 00000000000..08286e4afda
--- /dev/null
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/FooterOnlyString.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/FooterOnlyString.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/FooterOnlyString.xaml.cs
new file mode 100644
index 00000000000..c31cfcf4e3b
--- /dev/null
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/FooterOnlyString.xaml.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.HeaderFooterGalleries
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class FooterOnlyString : ContentPage
+ {
+ readonly DemoFilteredItemSource _demoFilteredItemSource = new DemoFilteredItemSource(20);
+
+ public FooterOnlyString()
+ {
+ InitializeComponent();
+
+ CollectionView.ItemTemplate = ExampleTemplates.PhotoTemplate();
+ CollectionView.ItemsSource = _demoFilteredItemSource.Items;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/HeaderFooterGallery.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/HeaderFooterGallery.cs
index 625f6fe3bd8..ee2a11b94de 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/HeaderFooterGallery.cs
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/HeaderFooterGalleries/HeaderFooterGallery.cs
@@ -20,7 +20,7 @@ public HeaderFooterGallery()
GalleryBuilder.NavButton("Header/Footer (Forms View)", () => new HeaderFooterView(), Navigation),
GalleryBuilder.NavButton("Header/Footer (Template)", () => new HeaderFooterTemplate(), Navigation),
GalleryBuilder.NavButton("Header/Footer (Grid)", () => new HeaderFooterGrid(), Navigation),
- GalleryBuilder.NavButton("Header/Footer (Grid Horizontal)", () => new HeaderFooterGridHorizontal(), Navigation),
+ GalleryBuilder.NavButton("Footer Only (String)", () => new FooterOnlyString(), Navigation),
}
}
};
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/ObservableCodeCollectionViewGallery.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/ObservableCodeCollectionViewGallery.cs
index 5fac776cfd6..00517e763a0 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/ObservableCodeCollectionViewGallery.cs
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/ObservableCodeCollectionViewGallery.cs
@@ -25,7 +25,8 @@ public ObservableCodeCollectionViewGallery(ItemsLayoutOrientation orientation =
var itemTemplate = ExampleTemplates.PhotoTemplate();
- var collectionView = new CollectionView {ItemsLayout = itemsLayout, ItemTemplate = itemTemplate, AutomationId = "collectionview" };
+ var collectionView = new CollectionView {ItemsLayout = itemsLayout, ItemTemplate = itemTemplate,
+ AutomationId = "collectionview", Header = "This is the header" };
var generator = new ItemsSourceGenerator(collectionView, initialItems, ItemsSourceType.ObservableCollection);
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/MultipleBoundSelection.xaml b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/MultipleBoundSelection.xaml
index d78cf9581ea..b7d8551f973 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/MultipleBoundSelection.xaml
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/MultipleBoundSelection.xaml
@@ -17,7 +17,7 @@
-
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/PreselectedItemGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/PreselectedItemGallery.xaml
index 35b4a39f73e..ac831d5a67d 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/PreselectedItemGallery.xaml
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/PreselectedItemGallery.xaml
@@ -15,7 +15,7 @@
-
+
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/PreselectedItemsGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/PreselectedItemsGallery.xaml
index 9589f241b4b..2cb9cc8c6a4 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/PreselectedItemsGallery.xaml
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/PreselectedItemsGallery.xaml
@@ -7,7 +7,7 @@
-
+
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/SelectionChangedCommandParameter.xaml b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/SelectionChangedCommandParameter.xaml
index 959191c4d3d..1c127820d10 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/SelectionChangedCommandParameter.xaml
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/SelectionGalleries/SelectionChangedCommandParameter.xaml
@@ -9,8 +9,8 @@
-
-
-
+
diff --git a/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj b/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj
index e6cc05f3182..c0ec8fdee84 100644
--- a/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj
+++ b/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj
@@ -56,11 +56,17 @@
MSBuild:UpdateDesignTimeXaml
+
+ MSBuild:UpdateDesignTimeXaml
+
+
+ MSBuild:UpdateDesignTimeXaml
+
MSBuild:UpdateDesignTimeXaml
- MSBuild:UpdateDesignTimeXaml
+ MSBuild:UpdateDesignTimeXaml
MSBuild:UpdateDesignTimeXaml
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/AdapterNotifier.cs b/Xamarin.Forms.Platform.Android/CollectionView/AdapterNotifier.cs
new file mode 100644
index 00000000000..cea6d238c7f
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/CollectionView/AdapterNotifier.cs
@@ -0,0 +1,55 @@
+using Android.Support.V7.Widget;
+
+namespace Xamarin.Forms.Platform.Android
+{
+ // Passes change notifications directly through to a RecyclerView.Adapter
+ internal class AdapterNotifier : ICollectionChangedNotifier
+ {
+ readonly RecyclerView.Adapter _adapter;
+
+ public AdapterNotifier(RecyclerView.Adapter adapter)
+ {
+ _adapter = adapter;
+ }
+
+ public void NotifyDataSetChanged()
+ {
+ _adapter.NotifyDataSetChanged();
+ }
+
+ public void NotifyItemChanged(IItemsViewSource source, int startIndex)
+ {
+ _adapter.NotifyItemChanged(startIndex);
+ }
+
+ public void NotifyItemInserted(IItemsViewSource source, int startIndex)
+ {
+ _adapter.NotifyItemInserted(startIndex);
+ }
+
+ public void NotifyItemMoved(IItemsViewSource source, int fromPosition, int toPosition)
+ {
+ _adapter.NotifyItemMoved(fromPosition, toPosition);
+ }
+
+ public void NotifyItemRangeChanged(IItemsViewSource source, int start, int end)
+ {
+ _adapter.NotifyItemRangeChanged(start, end);
+ }
+
+ public void NotifyItemRangeInserted(IItemsViewSource source, int startIndex, int count)
+ {
+ _adapter.NotifyItemRangeInserted(startIndex, count);
+ }
+
+ public void NotifyItemRangeRemoved(IItemsViewSource source, int startIndex, int count)
+ {
+ _adapter.NotifyItemRangeRemoved(startIndex, count);
+ }
+
+ public void NotifyItemRemoved(IItemsViewSource source, int startIndex)
+ {
+ _adapter.NotifyItemRemoved(startIndex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/CarouselViewRenderer.cs b/Xamarin.Forms.Platform.Android/CollectionView/CarouselViewRenderer.cs
index a4ce410ce66..3432295a1b2 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/CarouselViewRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/CarouselViewRenderer.cs
@@ -4,7 +4,7 @@
namespace Xamarin.Forms.Platform.Android
{
- public class CarouselViewRenderer : ItemsViewRenderer
+ public class CarouselViewRenderer : ItemsViewRenderer, IItemsViewSource>
{
// TODO hartez 2018/08/29 17:13:17 Does this need to override SelectLayout so it ignores grids? (Yes, and so it can warn on unknown layouts)
@@ -23,7 +23,7 @@ protected override void UpdateItemsSource()
// But for the Carousel, we want it to create the items to fit the width/height of the viewport
// So we give it an alternate delegate for creating the views
- ItemsViewAdapter = new ItemsViewAdapter(ItemsView,
+ ItemsViewAdapter = new ItemsViewAdapter(ItemsView,
(view, context) => new SizedItemContentView(context, () => Width, () => Height));
SwapAdapter(ItemsViewAdapter, false);
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/CollectionViewRenderer.cs b/Xamarin.Forms.Platform.Android/CollectionView/CollectionViewRenderer.cs
index 53bf890599a..4f71733a53d 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/CollectionViewRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/CollectionViewRenderer.cs
@@ -1,9 +1,8 @@
using Android.Content;
-using Android.Graphics;
namespace Xamarin.Forms.Platform.Android
{
- public class CollectionViewRenderer : SelectableItemsViewRenderer
+ public class CollectionViewRenderer : GroupableItemsViewRenderer, IGroupableItemsViewSource>
{
public CollectionViewRenderer(Context context) : base(context)
{
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/EmptySource.cs b/Xamarin.Forms.Platform.Android/CollectionView/EmptySource.cs
index 0fe83c973cc..6c037992091 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/EmptySource.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/EmptySource.cs
@@ -6,11 +6,42 @@ sealed internal class EmptySource : IItemsViewSource
{
public int Count => 0;
- public object this[int index] => throw new IndexOutOfRangeException("IItemsViewSource is empty");
+ public bool HasHeader { get; set; }
+ public bool HasFooter { get; set; }
public void Dispose()
{
-
+
+ }
+
+ public bool IsHeader(int index)
+ {
+ return HasHeader && index == 0;
+ }
+
+ public bool IsFooter(int index)
+ {
+ if (!HasFooter)
+ {
+ return false;
+ }
+
+ if (HasHeader)
+ {
+ return index == 1;
+ }
+
+ return index == 0;
+ }
+
+ public int GetPosition(object item)
+ {
+ return -1;
+ }
+
+ public object GetItem(int position)
+ {
+ throw new IndexOutOfRangeException("IItemsViewSource is empty");
}
}
}
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/EmptyViewAdapter.cs b/Xamarin.Forms.Platform.Android/CollectionView/EmptyViewAdapter.cs
index 0b86f3dc755..e11066980b2 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/EmptyViewAdapter.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/EmptyViewAdapter.cs
@@ -101,7 +101,7 @@ public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int
}
var itemContentView = new SizedItemContentView(parent.Context, () => parent.Width, () => parent.Height);
- return new TemplatedItemViewHolder(itemContentView, template);
+ return new TemplatedItemViewHolder(itemContentView, template, isSelectionEnabled: false);
}
public override int GetItemViewType(int position)
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/GridLayoutSpanSizeLookup.cs b/Xamarin.Forms.Platform.Android/CollectionView/GridLayoutSpanSizeLookup.cs
index 346f0d4ca79..e52c57af65a 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/GridLayoutSpanSizeLookup.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/GridLayoutSpanSizeLookup.cs
@@ -17,7 +17,8 @@ public override int GetSpanSize(int position)
{
var itemViewType = _recyclerView.GetAdapter().GetItemViewType(position);
- if (itemViewType == ItemViewType.Header || itemViewType == ItemViewType.Footer)
+ if (itemViewType == ItemViewType.Header || itemViewType == ItemViewType.Footer
+ || itemViewType == ItemViewType.GroupHeader || itemViewType == ItemViewType.GroupFooter)
{
return _gridItemsLayout.Span;
}
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/GroupableItemsViewAdapter.cs b/Xamarin.Forms.Platform.Android/CollectionView/GroupableItemsViewAdapter.cs
new file mode 100644
index 00000000000..2b0165fd688
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/CollectionView/GroupableItemsViewAdapter.cs
@@ -0,0 +1,67 @@
+using System;
+using Android.Content;
+using Android.Support.V7.Widget;
+using Android.Views;
+
+namespace Xamarin.Forms.Platform.Android
+{
+ public class GroupableItemsViewAdapter : SelectableItemsViewAdapter
+ where TItemsView : GroupableItemsView
+ where TItemsViewSource : IGroupableItemsViewSource
+ {
+ internal GroupableItemsViewAdapter(TItemsView groupableItemsView,
+ Func createView = null) : base(groupableItemsView, createView)
+ {
+ }
+
+ protected override TItemsViewSource CreateItemsSource()
+ {
+ return (TItemsViewSource)ItemsSourceFactory.Create(ItemsView, this);
+ }
+
+ public override int GetItemViewType(int position)
+ {
+ if (ItemsSource.IsGroupHeader(position))
+ {
+ return ItemViewType.GroupHeader;
+ }
+
+ if (ItemsSource.IsGroupFooter(position))
+ {
+ return ItemViewType.GroupFooter;
+ }
+
+ return base.GetItemViewType(position);
+ }
+
+ public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
+ {
+ var context = parent.Context;
+
+ if (viewType == ItemViewType.GroupHeader)
+ {
+ var itemContentView = new ItemContentView(context);
+ return new TemplatedItemViewHolder(itemContentView, ItemsView.GroupHeaderTemplate, isSelectionEnabled: false);
+ }
+
+ if (viewType == ItemViewType.GroupFooter)
+ {
+ var itemContentView = new ItemContentView(context);
+ return new TemplatedItemViewHolder(itemContentView, ItemsView.GroupFooterTemplate, isSelectionEnabled: false);
+ }
+
+ return base.OnCreateViewHolder(parent, viewType);
+ }
+
+ public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
+ {
+ if (holder is TemplatedItemViewHolder templatedItemViewHolder &&
+ (ItemsSource.IsGroupFooter(position) || ItemsSource.IsGroupHeader(position)))
+ {
+ BindTemplatedItemViewHolder(templatedItemViewHolder, ItemsSource.GetItem(position));
+ }
+
+ base.OnBindViewHolder(holder, position);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/GroupableItemsViewRenderer.cs b/Xamarin.Forms.Platform.Android/CollectionView/GroupableItemsViewRenderer.cs
new file mode 100644
index 00000000000..28daa5e7828
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/CollectionView/GroupableItemsViewRenderer.cs
@@ -0,0 +1,32 @@
+using System;
+using System.ComponentModel;
+using Android.Content;
+
+namespace Xamarin.Forms.Platform.Android
+{
+ public class GroupableItemsViewRenderer : SelectableItemsViewRenderer
+ where TItemsView : GroupableItemsView
+ where TAdapter : GroupableItemsViewAdapter
+ where TItemsViewSource : IGroupableItemsViewSource
+ {
+ public GroupableItemsViewRenderer(Context context) : base(context)
+ {
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
+ {
+ base.OnElementPropertyChanged(sender, changedProperty);
+
+ if (changedProperty.IsOneOf(GroupableItemsView.IsGroupedProperty,
+ GroupableItemsView.GroupFooterTemplateProperty, GroupableItemsView.GroupHeaderTemplateProperty))
+ {
+ UpdateItemsSource();
+ }
+ }
+
+ protected override TAdapter CreateAdapter()
+ {
+ return (TAdapter)new GroupableItemsViewAdapter(ItemsView);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/ICollectionChangedNotifier.cs b/Xamarin.Forms.Platform.Android/CollectionView/ICollectionChangedNotifier.cs
new file mode 100644
index 00000000000..b2a25480e4e
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/CollectionView/ICollectionChangedNotifier.cs
@@ -0,0 +1,15 @@
+namespace Xamarin.Forms.Platform.Android
+{
+ // Lets observable items sources notify observers about dataset changes
+ internal interface ICollectionChangedNotifier
+ {
+ void NotifyDataSetChanged();
+ void NotifyItemChanged(IItemsViewSource source, int startIndex);
+ void NotifyItemInserted(IItemsViewSource source, int startIndex);
+ void NotifyItemMoved(IItemsViewSource source, int fromPosition, int toPosition);
+ void NotifyItemRangeChanged(IItemsViewSource source, int start, int end);
+ void NotifyItemRangeInserted(IItemsViewSource source, int startIndex, int count);
+ void NotifyItemRangeRemoved(IItemsViewSource source, int startIndex, int count);
+ void NotifyItemRemoved(IItemsViewSource source, int startIndex);
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/IItemsViewSource.cs b/Xamarin.Forms.Platform.Android/CollectionView/IItemsViewSource.cs
index 3cf0ef75f9d..46a33ce257e 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/IItemsViewSource.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/IItemsViewSource.cs
@@ -2,9 +2,23 @@
namespace Xamarin.Forms.Platform.Android
{
- internal interface IItemsViewSource : IDisposable
+ public interface IItemsViewSource : IDisposable
{
int Count { get; }
- object this[int index] { get; }
+
+ int GetPosition(object item);
+ object GetItem(int position);
+
+ bool HasHeader { get; set; }
+ bool HasFooter { get; set; }
+
+ bool IsHeader(int position);
+ bool IsFooter(int position);
+ }
+
+ public interface IGroupableItemsViewSource : IItemsViewSource
+ {
+ bool IsGroupHeader(int position);
+ bool IsGroupFooter(int position);
}
}
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/ItemContentView.cs b/Xamarin.Forms.Platform.Android/CollectionView/ItemContentView.cs
index 6827c5ae447..61513655965 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/ItemContentView.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/ItemContentView.cs
@@ -4,7 +4,7 @@
namespace Xamarin.Forms.Platform.Android
{
- internal class ItemContentView : ViewGroup
+ public class ItemContentView : ViewGroup
{
protected IVisualElementRenderer Content;
Size? _size;
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/ItemViewType.cs b/Xamarin.Forms.Platform.Android/CollectionView/ItemViewType.cs
index 947480e1a8e..07c5700d45f 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/ItemViewType.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/ItemViewType.cs
@@ -6,5 +6,7 @@ public static class ItemViewType
public const int TemplatedItem = 42;
public const int Header = 43;
public const int Footer = 44;
+ public const int GroupHeader = 45;
+ public const int GroupFooter = 46;
}
}
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/CollectionView/ItemsSourceFactory.cs b/Xamarin.Forms.Platform.Android/CollectionView/ItemsSourceFactory.cs
index 5d3d8fa3df5..a03fe0af84c 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/ItemsSourceFactory.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/ItemsSourceFactory.cs
@@ -7,7 +7,7 @@ namespace Xamarin.Forms.Platform.Android
{
internal static class ItemsSourceFactory
{
- public static IItemsViewSource Create(IEnumerable itemsSource, RecyclerView.Adapter adapter)
+ public static IItemsViewSource Create(IEnumerable itemsSource, ICollectionChangedNotifier notifier)
{
if (itemsSource == null)
{
@@ -16,14 +16,33 @@ public static IItemsViewSource Create(IEnumerable itemsSource, RecyclerView.Adap
switch (itemsSource)
{
- // TODO hartez ObservableItemSource should be taking an INotifyCollectionChanged in its constructor
case IList _ when itemsSource is INotifyCollectionChanged:
- return new ObservableItemsSource(itemsSource as IList, adapter);
+ return new ObservableItemsSource(itemsSource as IList, notifier);
case IEnumerable