ListView 交互性

Xamarin.FormsListView 类支持用户与它呈现的数据进行交互。

选择和点击

ListView 选择模式是通过将 ListView.SelectionMode 属性设置为 ListViewSelectionMode 枚举的值来控制的:

  • Single 指示可以选择单个项,其中突出显示了所选项。 这是默认值。
  • None 指示无法选择项。

当用户点击某个项时,将触发两个事件:

点击同一个项两次将触发两个 ItemTapped 事件,但只会触发一个 ItemSelected 事件。

注意

ItemTappedEventArgs 类包含 ItemTapped 事件的事件参数,具有 GroupItem 属性,以及 ItemIndex 属性,其值表示被点击项的 ListView 中的索引。 同样,SelectedItemChangedEventArgs 类包含 ItemSelected 事件的事件参数,具有 SelectedItem 属性,以及 SelectedItemIndex 属性,其值表示选定项的 ListView 中的索引。

当属性 SelectionMode 设置为 Single 时,可以选择 ListView 中的项,ItemSelectedItemTapped 事件将触发,SelectedItem 属性将设置为所选项的值。

SelectionMode 属性设置为 None 时,无法选择 ListView 中的项,ItemSelected 事件将不会触发,SelectedItem 属性将保持为 null。 但是,仍将触发 ItemTapped 事件,被点击的项将在点击期间短暂突出显示。

选择了某个项且 SelectionMode 属性从 Single 更改为 None 后,SelectedItem 属性将设置为 nullItemSelected 事件将与 null 项一起触发。

以下屏幕截图显示了 ListView 和默认选择模式:

已启用选择功能的 ListView

禁用选择

若要禁用 ListView 选择,请将 SelectionMode 属性设置为 None

<ListView ... SelectionMode="None" />
var listView = new ListView { ... SelectionMode = ListViewSelectionMode.None };

上下文操作

通常,用户希望对 ListView 中的项执行操作。 例如,想一想邮件应用中的电子邮件列表。 在 iOS 上,可以轻扫以删除邮件:

具有上下文操作的 ListView

上下文操作可以在 C# 和 XAML 中实现。 在下面你将找到两者的特定指南,但首先让我们看看它们的一些关键实现细节。

上下文操作是使用 MenuItem 元素创建的。 MenuItems 对象的点击事件是由 MenuItem 本身引发的,而不是 ListView。 这不同于单元格的点击事件的处理方式,其中 ListView 会引发事件而不是单元格。 由于 ListView 引发事件,因此其事件处理程序会获得关键信息,例如已选择或点击了哪个项。

默认情况下,MenuItem 无法知道它所属的单元格。 CommandParameter 属性在 MenuItem 上可用,用于存储对象,例如 MenuItemViewCell 背后的对象。 可以在 XAML 和 C# 中设置 CommandParameter 属性。

XAML

MenuItem 元素可以在 XAML 集合中创建。 下面的 XAML 演示了一个实现两个上下文操作的自定义单元格:

<ListView x:Name="ContextDemoList">
  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
         <ViewCell.ContextActions>
            <MenuItem Clicked="OnMore"
                      CommandParameter="{Binding .}"
                      Text="More" />
            <MenuItem Clicked="OnDelete"
                      CommandParameter="{Binding .}"
                      Text="Delete" IsDestructive="True" />
         </ViewCell.ContextActions>
         <StackLayout Padding="15,0">
              <Label Text="{Binding title}" />
         </StackLayout>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

在代码隐藏文件中,确保实现 Clicked 方法:

public void OnMore (object sender, EventArgs e)
{
    var mi = ((MenuItem)sender);
    DisplayAlert("More Context Action", mi.CommandParameter + " more context action", "OK");
}

public void OnDelete (object sender, EventArgs e)
{
    var mi = ((MenuItem)sender);
    DisplayAlert("Delete Context Action", mi.CommandParameter + " delete context action", "OK");
}

注意

适用于 Android 的 NavigationPageRenderer 有可替代的 UpdateMenuItemIcon 方法,可以用来从自定义的 Drawable 加载图标。 使用此替代方法可以将 SVG 图像用作 Android 中 MenuItem 实例上的图标。

代码

上下文操作可以在任何 Cell 子类中实现(只要它不用作组标头),方法是创建 MenuItem 实例并将其添加到单元格的 ContextActions 集合中。 可以为上下文操作配置以下属性:

  • Text – 菜单项中显示的字符串。
  • Clicked – 单击项时的事件。
  • IsDestructive –(可选)为 true 时在 iOS 上以不同方式呈现。

可以将多个上下文操作添加到单元格,但只应有一个操作将 IsDestructive 设置为 true。 以下代码演示如何将上下文操作添加到 ViewCell

var moreAction = new MenuItem { Text = "More" };
moreAction.SetBinding (MenuItem.CommandParameterProperty, new Binding ("."));
moreAction.Clicked += async (sender, e) =>
{
    var mi = ((MenuItem)sender);
    Debug.WriteLine("More Context Action clicked: " + mi.CommandParameter);
};

var deleteAction = new MenuItem { Text = "Delete", IsDestructive = true }; // red background
deleteAction.SetBinding (MenuItem.CommandParameterProperty, new Binding ("."));
deleteAction.Clicked += async (sender, e) =>
{
    var mi = ((MenuItem)sender);
    Debug.WriteLine("Delete Context Action clicked: " + mi.CommandParameter);
};
// add to the ViewCell's ContextActions property
ContextActions.Add (moreAction);
ContextActions.Add (deleteAction);

下拉以刷新

用户已经习惯于下拉数据列表就会刷新该列表。 ListView 控件直接支持此功能。 若要启用拉动刷新功能,请将 IsPullToRefreshEnabled 设置为 true

<ListView ...
          IsPullToRefreshEnabled="true" />

等效 C# 代码如下:

listView.IsPullToRefreshEnabled = true;

刷新期间会显示一个旋转器,默认为黑色。 但是,通过将 RefreshControlColor 属性设置为 Color,可以在 iOS 和 Android 上更改旋转器颜色:

<ListView ...
          IsPullToRefreshEnabled="true"
          RefreshControlColor="Red" />

等效 C# 代码如下:

listView.RefreshControlColor = Color.Red;

以下屏幕截图显示拉动刷新,用户正在拉动:

ListView 下拉以刷新正在进行中

以下屏幕截图显示用户释放拉动后的拉动刷新,其中显示了旋转器,而 ListView 正在更新:

ListView 下拉以刷新完成

ListView 会触发 Refreshing 事件以启动刷新,而 IsRefreshing 属性将设置为 true。 刷新 ListView 的内容所需的任何代码应进而由 Refreshing 事件的事件处理程序执行,或由 RefreshCommand 执行的方法执行。 ListView 刷新后,IsRefreshing 属性应设置为 false,或应调用 EndRefresh 方法,以指示刷新已完成。

注意

定义 RefreshCommand 时,可以指定命令的 CanExecute 方法以启用或禁用该命令。

检测滚动

ListView 定义 Scrolled 事件,它触发时指示发生了滚动。 以下 XAML 示例显示为 Scrolled 事件设置事件处理程序的 ListView

<ListView Scrolled="OnListViewScrolled">
    ...
</ListView>

等效 C# 代码如下:

ListView listView = new ListView();
listView.Scrolled += OnListViewScrolled;

在此代码示例中,Scrolled 事件触发时,将执行 OnListViewScrolled 事件处理程序:

void OnListViewScrolled(object sender, ScrolledEventArgs e)
{
    Debug.WriteLine("ScrollX: " + e.ScrollX);
    Debug.WriteLine("ScrollY: " + e.ScrollY);  
}

OnListViewScrolled 事件处理程序会输出伴随该事件的 ScrolledEventArgs 对象的值。