ListView 外观

除了自定义列表中每行的 ViewCell 实例之外,Xamarin.FormsListView 还允许你自定义列表的呈现方式。

分组

以连续滚动列表形式呈现时,大量数据可能会变得难以处理。 在这些情况下,启用分组可以通过更好地组织内容和激活特定于平台的控件来使数据导航变得更加容易,从而改善用户体验。

ListView 激活分组时,将为每个组添加一个标题行。

若要启用分组功能,请执行以下操作:

  • 创建列表列表(组列表,每个组都是元素列表)。
  • ListViewItemsSource 设置为该列表。
  • IsGroupingEnabled 设置为 true。
  • GroupDisplayBinding 设置为绑定到用作组标题的组属性。
  • [可选] 将 GroupShortNameBinding 设置为绑定到用作组的短名称的组属性。 短名称用于跳转列表(iOS 上的右侧列)。

首先为组创建类:

public class PageTypeGroup : List<PageModel>
    {
        public string Title { get; set; }
        public string ShortName { get; set; } //will be used for jump lists
        public string Subtitle { get; set; }
        private PageTypeGroup(string title, string shortName)
        {
            Title = title;
            ShortName = shortName;
        }

        public static IList<PageTypeGroup> All { private set; get; }
    }

在上面的代码中,All 是将作为绑定源提供给 ListView 的列表。 TitleShortName 是将用于组标题的属性。

在此阶段,All 是一个空列表。 添加静态构造函数,以便在程序启动时填充列表:

static PageTypeGroup()
{
    List<PageTypeGroup> Groups = new List<PageTypeGroup> {
            new PageTypeGroup ("Alpha", "A"){
                new PageModel("Amelia", "Cedar", new switchCellPage(),""),
                new PageModel("Alfie", "Spruce", new switchCellPage(), "grapefruit.jpg"),
                new PageModel("Ava", "Pine", new switchCellPage(), "grapefruit.jpg"),
                new PageModel("Archie", "Maple", new switchCellPage(), "grapefruit.jpg")
            },
            new PageTypeGroup ("Bravo", "B"){
                new PageModel("Brooke", "Lumia", new switchCellPage(),""),
                new PageModel("Bobby", "Xperia", new switchCellPage(), "grapefruit.jpg"),
                new PageModel("Bella", "Desire", new switchCellPage(), "grapefruit.jpg"),
                new PageModel("Ben", "Chocolate", new switchCellPage(), "grapefruit.jpg")
            }
        };
        All = Groups; //set the publicly accessible list
}

在上面的代码中,我们还可以对 Groups 的元素调用 Add,这些元素是类型 PageTypeGroup 的实例。 此方法之所以可行,是因为 PageTypeGroup 继承自 List<PageModel>

下面是用于显示已分组列表的 XAML:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DemoListView.GroupingViewPage"
    <ContentPage.Content>
        <ListView  x:Name="GroupedView"
                   GroupDisplayBinding="{Binding Title}"
                   GroupShortNameBinding="{Binding ShortName}"
                   IsGroupingEnabled="true">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextCell Text="{Binding Title}"
                              Detail="{Binding Subtitle}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ContentPage.Content>
</ContentPage>

该 XAML 执行下列操作:

  • GroupShortNameBinding 设置为我们的组类中定义的 ShortName 属性
  • GroupDisplayBinding 设置为我们的组类中定义的 Title 属性
  • IsGroupingEnabled 设置为 true
  • ListViewItemsSource 更改为已分组列表

以下屏幕截图显示生成的 UI:

ListView 分组示例

自定义分组

如果列表中已启用分组,则还可以自定义组标头。

ListView 有一个用于定义行显示方式的 ItemTemplate 类似,ListView 有一个 GroupHeaderTemplate

此处显示了在 XAML 中自定义组标头的示例:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DemoListView.GroupingViewPage">
    <ContentPage.Content>
        <ListView x:Name="GroupedView"
                  GroupDisplayBinding="{Binding Title}"
                  GroupShortNameBinding="{Binding ShortName}"
                  IsGroupingEnabled="true">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextCell Text="{Binding Title}"
                              Detail="{Binding Subtitle}"
                              TextColor="#f35e20"
                              DetailColor="#503026" />
                </DataTemplate>
            </ListView.ItemTemplate>
            <!-- Group Header Customization-->
            <ListView.GroupHeaderTemplate>
                <DataTemplate>
                    <TextCell Text="{Binding Title}"
                              Detail="{Binding ShortName}"
                              TextColor="#f35e20"
                              DetailColor="#503026" />
                </DataTemplate>
            </ListView.GroupHeaderTemplate>
            <!-- End Group Header Customization -->
        </ListView>
    </ContentPage.Content>
</ContentPage>

页眉和页脚

ListView 可以呈现随列表元素滚动的页眉和页脚。 页眉和页脚可以是文本字符串或更复杂的布局。 此行为与分区组不同。

可以将 Header 和/或 Footer 设置为 string 值,也可以将它们设置为更复杂的布局。 还有 HeaderTemplateFooterTemplate 属性,可让你为支持数据绑定的页眉和页脚创建更复杂的布局。

若要创建基本的页眉/页脚,只需将“页眉”或“页脚”属性设置为要显示的文本即可。 在代码中:

ListView HeaderList = new ListView()
{
    Header = "Header",
    Footer = "Footer"
};

在 XAML 中:

<ListView x:Name="HeaderList" 
          Header="Header"
          Footer="Footer">
    ...
</ListView>

带标头和页脚的 ListView

若要创建自定义页眉和页脚,请定义“页眉”和“页脚”视图:

<ListView.Header>
    <StackLayout Orientation="Horizontal">
        <Label Text="Header"
               TextColor="Olive"
               BackgroundColor="Red" />
    </StackLayout>
</ListView.Header>
<ListView.Footer>
    <StackLayout Orientation="Horizontal">
        <Label Text="Footer"
               TextColor="Gray"
               BackgroundColor="Blue" />
    </StackLayout>
</ListView.Footer>

带自定义标头和页脚的 ListView

滚动条可见性

ListView 类具有 HorizontalScrollBarVisibilityVerticalScrollBarVisibility 属性,这些属性获取或设置一个 ScrollBarVisibility 值,该值表示水平或垂直滚动条何时可见。 这两个属性都可以设置为以下值:

  • Default 指示平台的默认滚动条行为,并且是 HorizontalScrollBarVisibilityVerticalScrollBarVisibility 属性的默认值。
  • Always 指示滚动条将可见,即使内容大小适合视图。
  • Never 指示滚动条将不可见,即使内容大小不适合视图。

行分隔符

在 iOS 和 Android 上,默认情况下,分隔线显示在 ListView 元素之间。 如果你希望在 iOS 和 Android 上隐藏分隔线,请在 ListView 上设置 SeparatorVisibility 属性。 SeparatorVisibility 的选项包括:

  • Default - 在 iOS 和 Android 上显示分隔线。
  • None - 在所有平台上隐藏分隔符。

默认可见性:

C#:

SeparatorDemoListView.SeparatorVisibility = SeparatorVisibility.Default;

XAML:

<ListView x:Name="SeparatorDemoListView" SeparatorVisibility="Default" />

具有默认行分隔符的 ListView

无:

C#:

SeparatorDemoListView.SeparatorVisibility = SeparatorVisibility.None;

XAML:

<ListView x:Name="SeparatorDemoListView" SeparatorVisibility="None" />

不带行分隔符的 ListView

还可以通过 SeparatorColor 属性设置分隔线的颜色:

C#:

SeparatorDemoListView.SeparatorColor = Color.Green;

XAML:

<ListView x:Name="SeparatorDemoListView" SeparatorColor="Green" />

具有绿色行分隔符的 ListView

注意

加载 ListView 后在 Android 上设置这些属性中的任何一个都会导致很大的性能损失。

行高

默认情况下,ListView 中的所有行都具有相同的高度。 ListView 有两个可用于更改该行为的属性:

  • HasUnevenRowstrue/false 值,如果设置为 true,则行具有不同的高度。 默认为 false
  • RowHeight – 当 HasUnevenRowsfalse 时设置每行的高度。

可以通过设置 ListView 上的 RowHeight 属性来设置所有行的高度。

自定义固定行高度

C#:

RowHeightDemoListView.RowHeight = 100;

XAML:

<ListView x:Name="RowHeightDemoListView" RowHeight="100" />

行高固定的 ListView

不均匀行

如果希望各行有不同的高度,可以将 HasUnevenRows 属性设置为 true。 将 HasUnevenRows 设置为 true 后,无需手动设置行高,因为高度将由 Xamarin.Forms 自动计算。

C#:

RowHeightDemoListView.HasUnevenRows = true;

XAML:

<ListView x:Name="RowHeightDemoListView" HasUnevenRows="true" />

行距不均匀的 ListView

在运行时重设行大小

如果 HasUnevenRows 属性设置为 true,则可在运行时以编程方式重设各个 ListView 行的大小。 Cell.ForceUpdateSize 方法会更新单元格的大小,即使单元格当前不可见,如以下代码示例所示:

void OnImageTapped (object sender, EventArgs args)
{
    var image = sender as Image;
    var viewCell = image.Parent.Parent as ViewCell;

    if (image.HeightRequest < 250) {
        image.HeightRequest = image.Height + 100;
        viewCell.ForceUpdateSize ();
    }
}

OnImageTapped 事件处理程序的执行是为了响应单元格中的 Image 被点击的操作,该处理程序会增加单元格中显示的 Image 的大小,使之便于查看。

具有运行时行大小调整功能的 ListView

警告

过度使用运行时行重设大小可能会导致性能下降。