CollectionView for Xamarin.Forms
This is a flexible ListView that has a grid and horizontal layout with reusable cells for Xamarin.Forms (Android / iOS).
iOS: iOS10
Android: version 5.1.1 (only FormsAppcompatActivity) / API22
https://www.nuget.org/packages/AiForms.CollectionView/
Install-Package AiForms.CollectionView -pre
You need to install this nuget package to .NETStandard project and each platform project.
To use on iOS, you need to write some code in AppDelegate.cs.
public override bool FinishedLaunching(UIApplication app, NSDictionary options) {
global::Xamarin.Forms.Forms.Init();
AiForms.Renderers.iOS.CollectionViewInit.Init(); //need to write here
LoadApplication(new App(new iOSInitializer()));
return base.FinishedLaunching(app, options);
}
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ai="clr-namespace:AiForms.Renderers;assembly=CollectionView"
x:Class="Sample.Views.Test">
<ai:GridCollectionView
ItemsSource="{Binding ItemsSource}" TouchFeedbackColor="Yellow"
ColumnWidth="100" ColumnHeight="1.0" >
<ListView.ItemTemplate>
<DataTemplate>
<ai:ContentCell>
<Label Text="{Binding Name}" />
</ai:ContentCell>
</DataTemplate>
</ListView.ItemTemplate>
</ai:GridCollectionView>
</ContentPage>
...
<ai:HCollectionView
ItemsSource="{Binding ItemsSource}" TouchFeedbackColor="Yellow"
ColumnWidth="100" HeightRequest="100" Spacing="4" IsInfinite="true" >
<ListView.ItemTemplate>
<DataTemplate>
<ai:ContentCell>
<Label Text="{Binding Name}" />
</ai:ContentCell>
</DataTemplate>
</ListView.ItemTemplate>
</ai:HCollectionView>
...
<ai:GridCollectionView
ItemsSource="{Binding ItemsSource}" TouchFeedbackColor="Yellow"
ColumnWidth="100" ColumnHeight="1.0"
IsGroupingEnabled="true" GroupHeaderHeight="36" >
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ai:ContentCell>
<Label Text="{Binding Category}" BackgroundColor="#E6DAB9" />
</ai:ContentCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ai:ContentCell>
<Label Text="{Binding Name}" />
</ai:ContentCell>
</DataTemplate>
</ListView.ItemTemplate>
</ai:GridCollectionView>
How to setting a Grouped HCollectionView is the same as the abobe.
Note that the root of DataTemplate must be arranged not a ViewCell but a ContentCell.
public class PhotoGroup : ObservableCollection<PhotoItem>
{
public string Head { get; set; }
public PhotoGroup(IEnumerable<PhotoItem> list) : base(list) { }
}
public class PhotoItem
{
public string PhotoUrl { get; set; }
public string Title { get; set; }
public string Category { get; set; }
}
public class SomeViewModel
{
public ObservableCollection<PhotoGroup> ItemsSource { get; } = new ObservableCollection<PhotoGroup>();
public SomeViewModel()
{
var list1 = new List<PhotoItem>();
for (var i = 0; i < 20; i++)
{
list1.Add(new PhotoItem
{
PhotoUrl = $"https://example.com/{i + 1}.jpg",
Title = $"Title {i + 1}",
Category = "AAA",
});
}
var list2 = new List<PhotoItem>();
for (var i = 20; i < 40; i++)
{
list2.Add(new PhotoItem
{
PhotoUrl = $"https://example.com/{i + 1}.jpg",
Title = $"Title {i + 1}",
Category = "BBB",
});
}
var group1 = new PhotoGroup(list1) { Head = "SectionA" };
var group2 = new PhotoGroup(list2) { Head = "SectionB" };
ItemsSource.Add(group1);
ItemsSource.Add(group2);
}
}
<ai:GridCollectionView
ItemsSource="{Binding ItemsSource}"
LoadMoreCommand="{Binding LoadMoreCommand}"
SetLoadMoreCompletion="{Binding SetLoadMoreCompletion}" >
...omitting
</ai:GridCollectionView>
public class SomeViewModel
{
public ObservableCollection<Item> ItemsSource { get; } = new ObservableCollection<Item>();
public Command LoadMoreCommand { get; set; }
public Action<bool> SetLoadMoreCompletion { get; set; }
public async Task LoadMoreCommandExecute()
{
var items = await WebApi.GetItems(10);
if(items.Count == 0)
{
SetLoadMoreCompletion(true); // All the items was loaded.
return;
}
foreach(var item in items)
{
ItemsSource.Add(item);
}
SetLoadMoreCompletion(false); // All the items is not still loaded.
}
}
ListView's Caching Strategy is available for both GridCollectionView and HCollectionView. Note that ListView uses RetainElement by default but CollectionView uses RecycleElement.
Since ListViewCachingStrategy is not a property, it must be set using "x:Arguments" syntax from XAML for changing to the other value.
<ai:HCollectionView ...>
<x:Arguments>
<ListViewCachingStrategy>RetainElement</ListViewCachingStrategy>
</x:Arguments>
...
</ai:HCollectionView>
Alternatively, it is set using code from C#.
var collectionView = new HCollectionView(ListViewCachingStrategy.RetainElement);
If you use images for a data template item, using FFImageLoading is recommended powerfully. Because this library doesn't contain the feature of such as dealing with images asynchronously and caching.
This is the ListView that lays out each item in a grid pattern. Though this is similar to WrapLayout, is different from it in that cells can be recycled.
ComputedWidth – ReadOnly
Note that this value can sometimes make 1 pixel difference from the actual width.
ComputedHeight – ReadOnly
This is the ListView that lays out each item horizontally. This can make the scroll circulated by setting IsInfinite property to true. HCollectionView also recycles cells.
ColumnWidth
Spacing
GroupHeaderWidth
IsInfinite
On iOS, it must be the number of cells enough to fill the container width. On Android, it could reach each edge if keep scrolling for so long, because it is semi-infinite.
HCollectionView height is decided by the HeightRequest value or itself size.
This is the object which allows methods for scrolling to be called from such as ViewModel. The following code is the example calling ScrollTo method from ViewModel:
public class SomeViewModel
{
public ObservableCollection<string> ItemsSource { get; } = new ObservableCollection<string>{ new List<string>{"A","B","C"} };
public IScrollController ScrollController { get; set; }
...
public GoToItem(int target)
{
// Scroll to the specified item position at the first visible area position with animation. If the target is 1, scroll to "B".
ScrollController.ScrollTo(ItemsSource[target],ScrollToPosition.Start,true);
}
public GoToStart()
{
ScrollController.ScrollToStart(true); // scroll to "A" with animation
}
public GoToEnd()
{
ScrollController.ScrollToEnd(true); // scroll to "C" with animation
}
}
<ai:GridCollectionView
ItemsSource="{Binding ItemsSource}"
ScrollController="{Binding ScrollController}"
...
>
</ai:GridCollectionView>
void ScrollTo(object sourceItem, ScrollToPosition scrollToPosition, bool animated = true)
void ScrollTo(object sourceItem, object sourceGroup ,ScrollToPosition scrollToPosition, bool animated = true)
void ScrollToStart(bool animated = true)
void ScrollToEnd(bool animated = true)
The MIT Licensed.
Some code is taken from Xamarin.Forms.