Xamarin CollectionView 分组Xamarin.Forms CollectionView Grouping

下载示例 下载示例Download Sample Download the sample

经常滚动列表中的大型数据集可能会变得难以使用。Large data sets can often become unwieldy when presented in a continually scrolling list. 在这种情况下,将数据组织成组可以更轻松地导航数据,从而改善用户体验。In this scenario, organizing the data into groups can improve the user experience by making it easier to navigate the data.

CollectionView支持显示分组数据,并定义以下属性,这些属性控制其显示方式:CollectionView supports displaying grouped data, and defines the following properties that control how it will be presented:

  • IsGrouped 类型 bool,指示是否应在组中显示基础数据。IsGrouped, of type bool, indicates whether the underlying data should be displayed in groups. 此属性的默认值为 falseThe default value of this property is false.
  • GroupHeaderTemplate 类型DataTemplate,要用于每个组的标头的模板。GroupHeaderTemplate, of type DataTemplate, the template to use for the header of each group.
  • GroupFooterTemplate 类型DataTemplate,要用于每个组的脚注的模板。GroupFooterTemplate, of type DataTemplate, the template to use for the footer of each group.

这些属性是由BindableProperty对象支持的,这意味着属性可以是数据绑定的目标。These properties are backed by BindableProperty objects, which means that the properties can be targets of data bindings.

以下屏幕截图显示了一个显示分组数据的CollectionViewThe following screenshots show a CollectionView displaying grouped data:

IOS 和 Android 上的 CollectionView 中的分组数据的屏幕截图Screenshot of a grouped data in a CollectionView, on iOS and Android

有关数据模板的详细信息,请参阅 Xamarin.Forms 数据模板For more information about data templates, see Xamarin.Forms Data Templates.

组数据Group data

必须先对数据进行分组,然后才能显示。Data must be grouped before it can be displayed. 这可以通过创建组列表来实现,其中每个组都是项的列表。This can be accomplished by creating a list of groups, where each group is a list of items. 组列表应为 IEnumerable<T> 集合,其中 T 定义两个数据片段:The list of groups should be an IEnumerable<T> collection, where T defines two pieces of data:

  • 组名称。A group name.
  • 定义属于组的项的 IEnumerable 集合。An IEnumerable collection that defines the items belonging to the group.

因此,对数据进行分组的过程是:The process for grouping data, therefore, is to:

  • 创建对单个项建模的类型。Create a type that models a single item.
  • 创建一个为一组项建模的类型。Create a type that models a single group of items.
  • 创建 IEnumerable<T> 集合,其中 T 是为一组项建模的类型。Create an IEnumerable<T> collection, where T is the type that models a single group of items. 因此,此集合为存储分组数据的组的集合。This collection is therefore a collection of groups, which stores the grouped data.
  • IEnumerable<T> 集合中添加数据。Add data to the IEnumerable<T> collection.

示例Example

在对数据进行分组时,第一步是创建一个为单个项建模的类型。When grouping data, the first step is to create a type that models a single item. 下面的示例演示示例应用程序中的 Animal 类:The following example shows the Animal class from the sample application:

public class Animal
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Details { get; set; }
    public string ImageUrl { get; set; }
}

@No__t_0 类对单个项建模。The Animal class models a single item. 然后就可以创建一组项的类型。A type that models a group of items can then be created. 下面的示例演示示例应用程序中的 AnimalGroup 类:The following example shows the AnimalGroup class from the sample application:

public class AnimalGroup : List<Animal>
{
    public string Name { get; private set; }

    public AnimalGroup(string name, List<Animal> animals) : base(animals)
    {
        Name = name;
    }
}

@No__t_0 类继承自 List<T> 类,并添加了一个表示组名称的 Name 属性。The AnimalGroup class inherits from the List<T> class and adds a Name property that represents the group name.

然后,可以创建组的 IEnumerable<T> 集合:An IEnumerable<T> collection of groups can then be created:

public List<AnimalGroup> Animals { get; private set; } = new List<AnimalGroup>();

此代码定义一个名为 Animals 的集合,其中集合中的每一项都是一个 AnimalGroup 对象。This code defines a collection named Animals, where each item in the collection is an AnimalGroup object. 每个 AnimalGroup 对象都包含一个名称和一个定义组中 Animal 对象的 List<Animal> 集合。Each AnimalGroup object comprises a name, and a List<Animal> collection that defines the Animal objects in the group.

然后,可以将分组数据添加到 Animals 集合中:Grouped data can then be added to the Animals collection:

Animals.Add(new AnimalGroup("Bears", new List<Animal>
{
    new Animal
    {
        Name = "American Black Bear",
        Location = "North America",
        Details = "Details about the bear go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/0/08/01_Schwarzbär.jpg"
    },
    new Animal
    {
        Name = "Asian Black Bear",
        Location = "Asia",
        Details = "Details about the bear go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG/180px-Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG"
    },
    // ...
}));

Animals.Add(new AnimalGroup("Monkeys", new List<Animal>
{
    new Animal
    {
        Name = "Baboon",
        Location = "Africa & Asia",
        Details = "Details about the monkey go here.",
        ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
    },
    new Animal
    {
        Name = "Capuchin Monkey",
        Location = "Central & South America",
        Details = "Details about the monkey go here.",
        ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
    },
    new Animal
    {
        Name = "Blue Monkey",
        Location = "Central and East Africa",
        Details = "Details about the monkey go here.",
        ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg"
    },
    // ...
}));

此代码在 Animals 集合中创建两个组。This code creates two groups in the Animals collection. 第一个 AnimalGroup 名为 Bears,它包含一个 List<Animal> 的熊详细信息集合。The first AnimalGroup is named Bears, and contains a List<Animal> collection of bear details. 第二个 AnimalGroup 称为 Monkeys,它包含一个 List<Animal> 的猴子详细信息集合。The second AnimalGroup is named Monkeys, and contains a List<Animal> collection of monkey details.

显示分组数据Display grouped data

如果数据已正确分组, CollectionView将显示已分组的数据,方法是将 IsGrouped 属性设置为 trueCollectionView will display grouped data, provided that the data has been grouped correctly, by setting the IsGrouped property to true:

<CollectionView ItemsSource="{Binding Animals}"
                IsGrouped="true">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid Padding="10">
                ...
                <Image Grid.RowSpan="2"
                       Source="{Binding ImageUrl}"
                       Aspect="AspectFill"
                       HeightRequest="60"
                       WidthRequest="60" />
                <Label Grid.Column="1"
                       Text="{Binding Name}"
                       FontAttributes="Bold" />
                <Label Grid.Row="1"
                       Grid.Column="1"
                       Text="{Binding Location}"
                       FontAttributes="Italic"
                       VerticalOptions="End" />
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

等效 C# 代码如下:The equivalent C# code is:

CollectionView collectionView = new CollectionView
{
    IsGrouped = true
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
// ...

@No__t_1中的每个项的外观都是通过将CollectionView.ItemTemplate属性设置为DataTemplate来定义的。The appearance of each item in the CollectionView is defined by setting the CollectionView.ItemTemplate property to a DataTemplate. 有关详细信息,请参阅定义项外观For more information, see Define item appearance.

备注

默认情况下, CollectionView将在组标头和表尾中显示组名称。By default, CollectionView will display the group name in the group header and footer. 可以通过自定义组头和组尾来更改此行为。This behavior can be changed by customizing the group header and group footer.

自定义组标头Customize the group header

可以通过将 CollectionView.GroupHeaderTemplate 属性设置为DataTemplate自定义每个组标头的外观:The appearance of each group header can be customized by setting the CollectionView.GroupHeaderTemplate property to a DataTemplate:

<CollectionView ItemsSource="{Binding Animals}"
                IsGrouped="true">
    ...
    <CollectionView.GroupHeaderTemplate>
        <DataTemplate>
            <Label Text="{Binding Name}"
                   BackgroundColor="LightGray"
                   FontSize="Large"
                   FontAttributes="Bold" />
        </DataTemplate>
    </CollectionView.GroupHeaderTemplate>
</CollectionView>

在此示例中,每个组标头设置为一个显示组名称的Label ,并设置了其他外观属性。In this example, each group header is set to a Label that displays the group name, and that has other appearance properties set. 以下屏幕截图显示了自定义的组标头:The following screenshots show the customized group header:

IOS 和 Android 上 CollectionView 中的自定义组标头的屏幕截图Screenshot of a customized group header in a CollectionView, on iOS and Android

可以通过将 CollectionView.GroupFooterTemplate 属性设置为DataTemplate自定义每个组脚注的外观:The appearance of each group footer can be customized by setting the CollectionView.GroupFooterTemplate property to a DataTemplate:

<CollectionView ItemsSource="{Binding Animals}"
                IsGrouped="true">
    ...
    <CollectionView.GroupFooterTemplate>
        <DataTemplate>
            <Label Text="{Binding Count, StringFormat='Total animals: {0:D}'}"
                   Margin="0,0,0,10" />
        </DataTemplate>
    </CollectionView.GroupFooterTemplate>
</CollectionView>

在此示例中,每个组页脚都设置为显示组中的项数的LabelIn this example, each group footer is set to a Label that displays the number of items in the group. 以下屏幕截图显示了自定义的组脚注:The following screenshots show the customized group footer:

IOS 和 Android 上的 CollectionView 中的自定义组脚注的屏幕截图Screenshot of a customized group footer in a CollectionView, on iOS and Android

空组Empty groups

CollectionView显示分组数据时,它会显示任何空组。When a CollectionView displays grouped data, it will display any groups that are empty. 此类组将连同组头和表尾一起显示,这表示该组为空。Such groups will be displayed with a group header and footer, indicating that the group is empty. 以下屏幕截图显示空组:The following screenshots show an empty group:

IOS 和 Android 上的 CollectionView 中的空组的屏幕截图Screenshot of an empty group in a CollectionView, on iOS and Android

备注

在 iOS 10 和更低版本中,空组的组头和组尾可能全部显示在 CollectionView 的顶部。On iOS 10 and lower, group headers and footers for empty groups may all be displayed at the top of the CollectionView.

无模板组Group without templates

CollectionView可以显示正确的分组数据,而不将CollectionView.ItemTemplate属性设置为DataTemplateCollectionView can display correctly grouped data without setting the CollectionView.ItemTemplate property to a DataTemplate:

<CollectionView ItemsSource="{Binding Animals}"
                IsGrouped="true" />

在此方案中,可以通过在对单个项建模的类型中重写 ToString 方法,并为一组项建模类型来显示有意义的数据。In this scenario, meaningful data can be displayed by overriding the ToString method in the type that models a single item, and the type that models a single group of items.