Xamarin.Forms CollectionView 布局
CollectionView
定义以下对布局进行控制的属性:
ItemsLayout
,类型为IItemsLayout
,指定要使用的布局。ItemSizingStrategy
,类型为ItemSizingStrategy
,指定要使用的项度量策略。
这些属性由 BindableProperty
对象提供支持,这意味着它们可以作为数据绑定的目标。
默认情况下,CollectionView
将在垂直列表中显示其项。 但是,可以使用以下任一布局:
- 垂直列表 – 随着添加新项而在垂直方向上增加的单列列表。
- 水平列表 – 随着添加新项而在水平方向增加的单行列表。
- 垂直网格 – 随着添加新项而在垂直方向上增加的多列网格。
- 水平网格 – 随着添加新项而在水平方向增加的多行网格。
可以通过将 ItemsLayout
属性设置为派生自 ItemsLayout
类的类来指定这些布局。 此类定义了以下属性:
Orientation
,类型为ItemsLayoutOrientation
,指定在添加项时CollectionView
展开的方向。SnapPointsAlignment
,类型为SnapPointsAlignment
,指定捕捉点与项的对齐方式。SnapPointsType
,类型为SnapPointsType
,指定滚动时捕捉点的行为。
这些属性由 BindableProperty
对象提供支持,这意味着这些属性可以作为数据绑定的目标。 有关对齐点的详细信息,请参阅 Xamarin.Forms CollectionView 滚动指南中的对齐点。
ItemsLayoutOrientation
枚举定义以下成员:
Vertical
指示CollectionView
在添加项时垂直扩展。Horizontal
指示CollectionView
在添加项时水平扩展。
LinearItemsLayout
类继承自 ItemsLayout
类,并定义类型为 double
的 ItemSpacing
属性,该属性表示每个项周围的空白空间。 此属性的默认值为 0,其值必须始终大于或等于 0。 LinearItemsLayout
类还定义静态 Vertical
和 Horizontal
成员。 这些成员可用于分别创建垂直列表或水平列表。 或者,可以创建 LinearItemsLayout
对象,将 ItemsLayoutOrientation
枚举成员指定为参数。
GridItemsLayout
类继承自 ItemsLayout
类,并定义以下属性:
VerticalItemSpacing
,类型为double
,表示每个项周围的垂直空白空间。 此属性的默认值为 0,并且其值必须始终大于或等于 0。HorizontalItemSpacing
,类型为double
,表示每个项周围的水平空白空间。 此属性的默认值为 0,并且其值必须始终大于或等于 0。Span
,类型为int
,表示要在网格中显示的列数或行数。 此属性的默认值为 1,并且其值必须始终大于或等于 1。
这些属性由 BindableProperty
对象提供支持,这意味着它们可以作为数据绑定的目标。
注意
CollectionView
使用本机布局引擎执行布局。
垂直列表
默认情况下,CollectionView
将在垂直列表布局中显示其项。 因此,无需设置 ItemsLayout
属性即可使用此布局:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<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>
但是,为了完整起见,在 XAML 中,可以通过将 CollectionView
的 ItemsLayout
属性设置为 VerticalList
,将其设置为在垂直列表中显示其项:
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="VerticalList">
...
</CollectionView>
或者,也可以通过将 ItemsLayout
属性设置为 LinearItemsLayout
对象,并将 Vertical
ItemsLayoutOrientation
枚举成员指定为 Orientation
属性值,来实现此布局:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" />
</CollectionView.ItemsLayout>
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
...
ItemsLayout = LinearItemsLayout.Vertical
};
这会生成单列列表,该列表会随着添加新项在垂直方向上增加:
水平列表
在 XAML 中,CollectionView
可以通过将其 ItemsLayout
属性设置为 HorizontalList
,在水平列表中显示其项:
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="HorizontalList">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
或者,也可以通过将 ItemsLayout
属性设置为 LinearItemsLayout
对象,并将 Horizontal
ItemsLayoutOrientation
枚举成员指定为 Orientation
属性值,来实现此布局:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" />
</CollectionView.ItemsLayout>
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
...
ItemsLayout = LinearItemsLayout.Horizontal
};
这会生成单行列表,该列表会随着添加新项而在水平方向增加:
垂直网格
在 XAML 中,CollectionView
可以通过将其 ItemsLayout
属性设置为 VerticalGrid
,在垂直网格中显示其项:
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="VerticalGrid, 2">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
或者,也可以通过将 ItemsLayout
属性设置为 GridItemsLayout
对象,将该对象的 Orientation
属性设置为 Vertical
来完成此布局:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
...
ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Vertical)
};
默认情况下,垂直 GridItemsLayout
将显示单列中的项。 但是,此示例将 GridItemsLayout.Span
属性设置为 2。 这将生成一个两列网格,该网格会随着添加新项而在垂直方向上增加:
水平网格
在 XAML 中,CollectionView
可以通过将其 ItemsLayout
属性设置为 HorizontalGrid
,在水平网格中显示其项:
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="HorizontalGrid, 4">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
或者,也可以通过将 ItemsLayout
属性设置为 GridItemsLayout
对象,将该对象的 Orientation
属性设置为 Horizontal
来完成此布局:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Horizontal"
Span="4" />
</CollectionView.ItemsLayout>
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
...
ItemsLayout = new GridItemsLayout(4, ItemsLayoutOrientation.Horizontal)
};
默认情况下,水平 GridItemsLayout
将在单行中显示项。 但是,此示例将 GridItemsLayout.Span
属性设置为 4。 这将生成一个四行网格,该网格会随着新项的添加而水平扩展:
页眉和页脚
CollectionView
可以显示随列表中的项一起滚动的页眉和页脚。 页眉和页脚可以是字符串、视图或 DataTemplate
对象。
CollectionView
定义用于指定页眉和页脚的以下属性:
object
类型的Header
指定将在列表开头显示的字符串、绑定或视图。DataTemplate
类型的HeaderTemplate
指定用于设置Header
格式的DataTemplate
。object
类型的Footer
指定将在列表末尾显示的字符串、绑定或视图。DataTemplate
类型的FooterTemplate
指定用于设置Footer
格式的DataTemplate
。
这些属性由 BindableProperty
对象提供支持,这意味着它们可以作为数据绑定的目标。
将页眉添加到从左到右水平扩展的布局中时,页眉会显示在列表的左侧。 同样,将页脚添加到从左到右水平扩展的布局时,页脚会显示在列表右侧。
在页眉和页脚中显示字符串
可以将 Header
和 Footer
属性设置为 string
值,如以下示例所示:
<CollectionView ItemsSource="{Binding Monkeys}"
Header="Monkeys"
Footer="2019">
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
Header = "Monkeys",
Footer = "2019"
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
此代码生成以下屏幕截图,其中页眉显示在 iOS 屏幕截图中,页脚显示在 Android 屏幕截图中:
在页眉和页脚中显示视图
可以将 Footer
和 Header
属性都设置为视图。 这可以是单个视图,也可以是包含多个子视图的视图。 以下示例显示 Header
和 Footer
属性,每个属性都设置为包含 Label
对象的 StackLayout
对象:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.Header>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Monkeys"
FontSize="Small"
FontAttributes="Bold" />
</StackLayout>
</CollectionView.Header>
<CollectionView.Footer>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Friends of Xamarin Monkey"
FontSize="Small"
FontAttributes="Bold" />
</StackLayout>
</CollectionView.Footer>
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
Header = new StackLayout
{
Children =
{
new Label { Text = "Monkeys", ... }
}
},
Footer = new StackLayout
{
Children =
{
new Label { Text = "Friends of Xamarin Monkey", ... }
}
}
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
此代码生成以下屏幕截图,其中页眉显示在 iOS 屏幕截图中,页脚显示在 Android 屏幕截图中:
显示模板化页眉和页脚
可以将 HeaderTemplate
和 FooterTemplate
属性设置为用于设置页眉和页脚格式的 DataTemplate
对象。 在此方案中,Header
和 Footer
属性必须绑定到要应用模板的当前源,如以下示例所示:
<CollectionView ItemsSource="{Binding Monkeys}"
Header="{Binding .}"
Footer="{Binding .}">
<CollectionView.HeaderTemplate>
<DataTemplate>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Monkeys"
FontSize="Small"
FontAttributes="Bold" />
</StackLayout>
</DataTemplate>
</CollectionView.HeaderTemplate>
<CollectionView.FooterTemplate>
<DataTemplate>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Friends of Xamarin Monkey"
FontSize="Small"
FontAttributes="Bold" />
</StackLayout>
</DataTemplate>
</CollectionView.FooterTemplate>
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
HeaderTemplate = new DataTemplate(() =>
{
return new StackLayout { };
}),
FooterTemplate = new DataTemplate(() =>
{
return new StackLayout { };
})
};
collectionView.SetBinding(ItemsView.HeaderProperty, ".");
collectionView.SetBinding(ItemsView.FooterProperty, ".");
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
此代码生成以下屏幕截图,其中页眉显示在 iOS 屏幕截图中,页脚显示在 Android 屏幕截图中:
项间距
默认情况下,CollectionView
中的每个项之间没有空格。 可以通过在 CollectionView
使用的项布局上设置属性更改此行为。
当 CollectionView
将其 ItemsLayout
属性设置为 LinearItemsLayout
对象时,可以将 LinearItemsLayout.ItemSpacing
属性设置为表示项之间空格的 double
值:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"
ItemSpacing="20" />
</CollectionView.ItemsLayout>
...
</CollectionView>
注意
LinearItemsLayout.ItemSpacing
属性设置验证回调集,可确保属性值始终大于或等于 0。
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
...
ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical)
{
ItemSpacing = 20
}
};
此代码生成一个垂直单列列表,各个项之间的间距为 20:
当 CollectionView
将其 ItemsLayout
属性设置为 GridItemsLayout
对象时,可以将 GridItemsLayout.VerticalItemSpacing
和 GridItemsLayout.HorizontalItemSpacing
属性设置为 double
值,这些值表示项之间的垂直和水平空白区域:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2"
VerticalItemSpacing="20"
HorizontalItemSpacing="30" />
</CollectionView.ItemsLayout>
...
</CollectionView>
注意
GridItemsLayout.VerticalItemSpacing
和 GridItemsLayout.HorizontalItemSpacing
属性设置了验证回调,这可确保属性的值始终大于或等于 0。
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
...
ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Vertical)
{
VerticalItemSpacing = 20,
HorizontalItemSpacing = 30
}
};
此代码生成一个垂直两列网格,各个项之间的垂直间距为 20,各个项之间水平间距为 30:
调整项大小
默认情况下,如果 DataTemplate
中的 UI 元素未指定固定大小,则单独测量和调整 CollectionView
中每个项的大小。 此行为(可以更改)由 CollectionView.ItemSizingStrategy
属性值指定。 可将此属性值设置为 ItemSizingStrategy
枚举成员中的一个:
MeasureAllItems
– 每个项都是单独测量的。 这是默认值。MeasureFirstItem
– 仅测量第一项,所有后续项的大小都与第一项相同。
重要
在所有项的大小均一致的情况下使用 MeasureFirstItem
大小调整策略将可以提高性能。
以下代码示例展示如何设置 ItemSizingStrategy
属性:
<CollectionView ...
ItemSizingStrategy="MeasureFirstItem">
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
...
ItemSizingStrategy = ItemSizingStrategy.MeasureFirstItem
};
动态调整项大小
在运行时可以通过更改 DataTemplate
中元素的布局相关属性,动态调整 CollectionView
中项的大小。 例如,以下代码示例更改 Image
对象的 HeightRequest
和 WidthRequest
属性:
void OnImageTapped(object sender, EventArgs e)
{
Image image = sender as Image;
image.HeightRequest = image.WidthRequest = image.HeightRequest.Equals(60) ? 100 : 60;
}
执行 OnImageTapped
事件处理程序以响应正在点击的 Image
对象,并更改图像尺寸,以便其更易于查看:
从右到左的布局
CollectionView
可按从右到左的流方向布局其内容,方法是将其 FlowDirection
属性设置为 RightToLeft
。 但是,最好在页面或根布局上设置 FlowDirection
属性,以便页面或根布局中的所有元素都响应流方向:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CollectionViewDemos.Views.VerticalListFlowDirectionPage"
Title="Vertical list (RTL FlowDirection)"
FlowDirection="RightToLeft">
<StackLayout Margin="20">
<CollectionView ItemsSource="{Binding Monkeys}">
...
</CollectionView>
</StackLayout>
</ContentPage>
包含父元素的元素其默认 FlowDirection
为 MatchParent
。 因此,CollectionView
从 StackLayout
继承 FlowDirection
属性值,而前者又从 ContentPage
继承 FlowDirection
属性值。 这会生成如以下屏幕截图所示的布局:
有关流方向的详细信息,请参阅从右到左本地化。