Category / Section
How to customize the ListView grouping with grid columns in Xamarin.Forms (SfListView)
2 mins read
You can customize grouping by a Comparer in GroupDescriptor and GroupHeader using the GroupHeaderTemplate with converter.
Here, the GroupHeader is customized as ListViewItem using the converter in GroupHeaderTemplate.
<syncfusion:SfListView x:Name="listView" GroupHeaderSize="300" AutoFitMode="DynamicHeight" SelectionMode="Single" ItemsSource="{Binding MemberDetails}"> <syncfusion:SfListView.GroupHeaderTemplate> <DataTemplate> <StackLayout BackgroundColor="LightGray"> <Image x:Name="ScrumMasterImage" Source="{Binding Converter={StaticResource Converter}, ConverterParameter=ScrumMasterImage}" VerticalOptions="Center" HeightRequest="80" WidthRequest="80" HorizontalOptions="CenterAndExpand" Margin="10" /> <Label x:Name="ScrumMasterRole" Text="{Binding Converter={StaticResource Converter}, ConverterParameter=ScrumMasterRole}" FontSize="20" HorizontalOptions="CenterAndExpand" VerticalOptions="Center"/> <Label x:Name="ScrumMasterName" Text="{Binding Converter={StaticResource Converter}, ConverterParameter=ScrumMasterName}" FontSize="18" Padding="0,0,0,10" HorizontalOptions="CenterAndExpand" VerticalOptions="Center"/> </StackLayout> </DataTemplate> </syncfusion:SfListView.GroupHeaderTemplate> </syncfusion:SfListView>
Converter, which designs the group header.
class Converter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) return null; string id = parameter as string; var groupResult = value as GroupResult; foreach (var item in groupResult.Items) { if(id == "ScrumMasterImage") { return (item as TeamInfo).MemberImage; } else if(id == "ScrumMasterRole") { return (item as TeamInfo).Role; } else if (id == "ScrumMasterName") { return (item as TeamInfo).MemberName; } } return null; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
The GridLayout defined in the LayoutManager with column count as 2 using the SpanCount property.
<syncfusion:SfListView x:Name="listView"> <syncfusion:SfListView.LayoutManager> <syncfusion:GridLayout SpanCount="2"/> </syncfusion:SfListView.LayoutManager> </syncfusion:SfListView>
The GroupDescriptor defined with comparer to sort the specific group always to be at the top of the rows.
public class Behavior : Behavior<SfListView> { protected override void OnAttachedTo(SfListView bindable) { bindable.DataSource.GroupDescriptors.Add(new GroupDescriptor() { PropertyName = "IsScrumMaster", Comparer = new GroupComparer() }); base.OnAttachedTo(bindable); } } public class GroupComparer : IComparer<GroupResult> { public int Compare(GroupResult x, GroupResult y) { if (x.Count > y.Count) { return 1; } else if (x.Count < y.Count) { return -1; } return 0; } }
QueryItemSize to reset the Height of the groups that are not needed to show in the view to zero.
public class Behavior : Behavior<SfListView> { protected override void OnAttachedTo(SfListView bindable) { bindable.QueryItemSize += Bindable_QueryItemSize; } private void Bindable_QueryItemSize(object sender, QueryItemSizeEventArgs e) { var bindingContext = (sender as SfListView).BindingContext as TeamInfoRepository; var collection = bindingContext.MemberDetails; var type = e.ItemType; if (type == ItemType.GroupHeader && (bool)(e.ItemData as GroupResult).Key) ; else if (type == ItemType.GroupHeader && !(bool)(e.ItemData as GroupResult).Key) { e.ItemSize = 0; e.Handled = true; } if (type == ItemType.Record) { var isManager = (e.ItemData as TeamInfo).IsScrumMaster; if (isManager) { e.ItemSize = 0; e.Handled = true; } } } protected override void OnDetachingFrom(SfListView bindable) { bindable.QueryItemSize -= Bindable_QueryItemSize; base.OnDetachingFrom(bindable); } }
Output