请教ListView中列表项用的android.R.layout.simple

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请教ListView中列表项用的android.R.layout.simple相关的知识,希望对你有一定的参考价值。

android listview与adapter用法
listview与adapter用法

一个ListView通常有两个职责。
(1)将数据填充到布局。
(2)处理用户的选择点击等操作。
第一点很好理解,ListView就是实现这个功能的。第二点也不难做到,在后面的学习中读者会发现,这非常简单。
一个ListView的创建需要3个元素。
(1)ListView中的每一列的View。
(2)填入View的数据或者图片等。
(3)连接数据与ListView的适配器。
也就是说,要使用ListView,首先要了解什么是适配器。适配器是一个连接数据和AdapterView(ListView就是一个典型的AdapterView,后面还会学习其他的)的桥梁,通过它能有效地实现数据与AdapterView的分离设置,使AdapterView与数据的绑定更加简便,修改更加方便
Android中提供了很多的Adapter,表4-5列出了常用的几个。
表4-5 常用适配器

Adapter

含义

ArrayAdapter<T>

用来绑定一个数组,支持泛型操作

SimpleAdapter

用来绑定在xml中定义的控件对应的数据

SimpleCursorAdapter

用来绑定游标得到的数据

BaseAdapter

通用的基础适配器

其实适配器还有很多,要注意的是,各种Adapter只不过是转换的方式和能力不一样而已。下面就通过使用不同的Adapter来为ListView绑定数据(SimpleCursorAdapter暂且不讲,后面讲SQLite时会介绍)。
4.12.1 ListView使用ArrayAdapter
用ArrayAdapter可以实现简单的ListView的数据绑定。默认情况下,ArrayAdapter绑定每个对象的toString值到layout中预先定义的TextView控件上。ArrayAdapter的使用非常简单。
参考技术A 这是Android系统内置的一种列表格式。

WPF 列表控件数据源绑定多个数据集合方法

在 WPF 用的多的列表控件如 ListBox 或 ListView 等,本文告诉大家在这些列表控件上进行绑定多个数据集合来源的多个实现方法。如有一个显示动物列表的控件,需要绑定的数据来源是阿猫和阿狗两个 ObservableCollection 列表,不在后台代码编写合并集合的代码情况下,可以通过 XAML 的编写,绑定多个数据集合

准备

在开始之前,咱先搭建一点测试使用的代码,假定咱有一个 列表控件 准备绑定到的数据源是两个 ObservableCollection 对象,下面来定义这两个 ObservableCollection 对象和对应的 阿猫和阿狗 的代码

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            for (int i = 0; i < 10; i++)
            {
                Dogs.Add(new Dog()
                {
                    Name = "Dog" + i
                });

                Cats.Add(new Cat()
                {
                    Name = "Cat" + i
                });
            }

            DataContext = this;
        }

        public ObservableCollection<Dog> Dogs { get; } = new ObservableCollection<Dog>();
        public ObservableCollection<Cat> Cats { get; } = new ObservableCollection<Cat>();
    }

    public class Dog : Animal
    {
    }

    public class Cat : Animal
    {
    }

    public class Animal
    {
        public string Name { get; set; }
    }

可以看到以上代码里面存在两个 ObservableCollection 对象,同时 MainWindow 的 DataContext 就是 MainWindow 对象。咱需要将两个 ObservableCollection 对象作为数据源,放在相同的一个 ListBox 里面

下面是多个不同的实现方式,解决如何在 WPF 中在 ListBox 或 ListView 绑定多个数据集合 ObservableCollection 对象

通过 CollectionViewSource 方式

在 ListView 或 ListBox 资源里面,添加 CollectionViewSource 绑定到集合里面,然后在 ItemsSource 使用 CompositeCollection 进行绑定,代码如下

    <ListBox>
      <ListBox.Resources>
        <CollectionViewSource x:Key="DogCollection" Source="{Binding Dogs}"/>
        <CollectionViewSource x:Key="CatCollection" Source="{Binding Cats}"/>
      </ListBox.Resources>
      <ListBox.ItemsSource>
        <CompositeCollection>
          <CollectionContainer Collection="{Binding Source={StaticResource DogCollection}}"/>
          <CollectionContainer Collection="{Binding Source={StaticResource CatCollection}}"/>
        </CompositeCollection>
      </ListBox.ItemsSource>

      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Name}"></TextBlock>
        </DataTemplate>
      </ListBox.ItemTemplate>

    </ListBox>

这个方法的优势在于可以完全使用 XAML 编写内容,但是缺点在于有重复的代码,如有多个绑定的集合对象,就需要在资源和 CompositeCollection 里面定义多个 CollectionViewSource 和 CollectionContainer 对象

如果绑定的集合数量不多,那么此写法还成,但如果集合数量比较多,而且需要不断变更顺序,那以上写法就有坑

此方法请参考 WPF 很少人知道的科技 - walterlv

通过 CompositeCollection 动态绑定

在 ListView 或 ListBox 的资源里面定义了 CompositeCollection 通过控件的 DataContext 绑定多个集合,代码如下

        <CompositeCollection x:Key="MyColl">
          <CollectionContainer Collection="{Binding DataContext.Dogs, Source={x:Reference MyList}}"/>
          <CollectionContainer Collection="{Binding DataContext.Cats, Source={x:Reference MyList}}"/>
        </CompositeCollection>

以上代码的 MyList 就是集合控件,此方法需要用到 x:Reference 获取对象的引用,同时需要通过 DataContext 的某个属性获取到对应的属性,全部代码如下

    <ListBox x:Name="MyList" ItemsSource="{DynamicResource MyColl}">
      <ListBox.Resources>
        <CompositeCollection x:Key="MyColl">
          <CollectionContainer Collection="{Binding DataContext.Dogs, Source={x:Reference MyList}}"/>
          <CollectionContainer Collection="{Binding DataContext.Cats, Source={x:Reference MyList}}"/>
        </CompositeCollection>
      </ListBox.Resources>
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Name}"></TextBlock>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>

对比上面的方法,此方法可以让绑定集合的代码只写一次,看起来代码更少一点。但不足的地方在于绑定 ItemsSource 需要用到 DynamicResource 的方式,相对性能不如上面方法。为什么需要 DynamicResource 资源?原因是资源本身定义在 Resources 里面。为什么资源需要定义在控件里面的 Resource 里面?原因是为了获取到控件的 x:Reference 对象。也就是说需要在控件创建出来之后,才能通过 x:Reference 获取控件,而控件的数据内容需要依赖资源的定义,因此也只有以上方式的写法

如果能从控件的上层容器拿到数据对象,那可以将资源定义在容器里面,通过 StaticResource 绑定到静态资源。如放在 Window 的 Resources 里

<Window x:Class="CibairyafocairluYerkinemde.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CibairyafocairluYerkinemde"
        mc:Ignorable="d"
        x:Name="Root"
        Title="MainWindow" Height="450" Width="800">
  <Window.Resources>
    <CompositeCollection x:Key="MyColl">
      <CollectionContainer Collection="{Binding DataContext.Dogs, Source={x:Reference Root}}"/>
      <CollectionContainer Collection="{Binding DataContext.Cats, Source={x:Reference Root}}"/>
    </CompositeCollection>
  </Window.Resources>

  <Grid>
   <ListBox x:Name="MyList" ItemsSource="{StaticResource MyColl}" >
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Name}"></TextBlock>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
  </Grid>
</Window>

以上写法没有啥缺点,也不存在动态资源的性能问题。但实际上在有动态资源下,性能问题也是很小的问题,对比渲染控件本身,动态绑定性能可以忽略

通过多绑定方法

此方法需要添加一点后台代码,定义 CompositeCollectionConverter 转换器,实现逻辑是通过多绑定的方法,将多个数据集合当成多个参数进行绑定

    <ListBox>
      <ListBox.ItemsSource>
        <MultiBinding Converter="{x:Static local:CompositeCollectionConverter.Default}">
          <Binding Path="Dogs" />
          <Binding Path="Cats" />
        </MultiBinding>
      </ListBox.ItemsSource>
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Name}"></TextBlock>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>

可以看到此方法的 XAML 代码量最小,只是需要一个辅助的 CompositeCollectionConverter 类,代码如下

    public class CompositeCollectionConverter : IMultiValueConverter
    {
        public static readonly CompositeCollectionConverter Default = new CompositeCollectionConverter();

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var compositeCollection = new CompositeCollection();
            foreach (var value in values)
            {
                if (value is IEnumerable enumerable)
                {
                    compositeCollection.Add(new CollectionContainer { Collection = enumerable });
                }
                else
                {
                    compositeCollection.Add(value);
                }
            }

            return compositeCollection;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("CompositeCollectionConverter ony supports oneway bindings");
        }
    }

可以将 CompositeCollectionConverter 放在库里面,这样就可以让 XAML 代码看起来简单

本文所有代码放在 githubgitee 欢迎小伙伴访问

参考

本文以上方法参考了如下博客

c# - CompositeCollection + CollectionContainer: Bind CollectionContainer.Collection to property of ViewModel that is used as DataTemplates DataType - Stack Overflow

wpf - How do you bind a CollectionContainer to a collection in a view model? - Stack Overflow

WPF 很少人知道的科技 - walterlv

以上是关于请教ListView中列表项用的android.R.layout.simple的主要内容,如果未能解决你的问题,请参考以下文章

【请教】关于 仿新浪微博下拉刷新Listview!!

C#中listview控件是啥东东??咋用的

按钮未显示在android的自定义列表视图中

Android listview 错误:您的内容必须有一个 ID 属性为“android.R.id.list”的 ListView,但我有两个 listview [重复]

ListFragment:运行时错误“您的内容必须有一个 id 属性为 'android.R.list' 的 ListView

您的内容必须有一个 ID 属性为“android.R.id.list”的 ListView