隐藏

使用 Xamarin.Android 自定义 ListView 的外观

发布:2021/10/14 15:11:46作者:管理员 来源:本站 浏览次数:1063

ListView 的外观由显示的行的布局决定。 若要更改 的外观 ListView ,请使用其他行布局。

内置行视图

可以使用 Android.Resource.Layout 引用 12 个内置视图:

  • TestListItem – 采用最小格式的单行文本。

  • SimpleListItem1 – 单行文本。

  • SimpleListItem2 – 两行文本。

  • SimpleSelectableListItem – 支持在 API 级别 11 中添加的单行或多 (项选择) 。

  • SimpleListItemActivated1 – 类似于 SimpleListItem1,但背景色指示何时在 API 级别 11 (添加行) 。

  • SimpleListItemActivated2 – 类似于 SimpleListItem2,但背景色指示何时在 API 级别 11 (中添加行) 。

  • SimpleListItemChecked – 显示选中标记以指示选择。

  • SimpleListItemMultipleChoice – 显示复选框以指示多选选项。

  • SimpleListItemSingleChoice – 显示单选按钮以指示相互排斥的选择。

  • TwoLineListItem – 两行文本。

  • ActivityListItem – 包含图像的单行文本。

  • SimpleExpandableListItem – 按类别对行进行分组,每个组都可以展开或折叠。

每个内置行视图都有一个与之关联的内置样式。 这些屏幕截图显示了每个视图的显示方式:

TestListItem、SimpleSelectableListItem、SimpleListitem1 和 SimpleListItem2 的屏幕截图。

SimpleListItemActivated1、SimpleListItemActivated2、SimpleListItemChecked 和 SimpleListItemMultipleChecked 的屏幕截图。

SimpleListItemSingleChoice、TwoLineListItem、ActivityListItem 和 SimpleExpandableListItem 的屏幕截图。

BuiltInViews 解决方案 (中的 BuiltInViews/HomeScreenAdapter.cs 示例文件) 包含用于生成不可展开的列表项屏幕的代码。 视图在 方法 GetView 中设置,如下所示:

C#
view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null); 

然后,可以通过引用标准控件标识符 来设置视图的属性, (下不设置视图不包含的属性,否则将引发 Text1 Text2 Icon Android.Resource.Id) :

C#
view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = item.Heading;
view.FindViewById<TextView>(Android.Resource.Id.Text2).Text = item.SubHeading;
view.FindViewById<ImageView>(Android.Resource.Id.Icon).SetImageResource(item.ImageResourceId); // only use with ActivityListItem 

BuiltInViews 解决方案) 中的 BuiltInExpandableViews/ExpandableScreenAdapter.cs 示例文件 (包含用于生成 SimpleExpandableListItem 屏幕的代码。 组视图在 方法中 GetGroupView 设置,如下所示:

C#
view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleExpandableListItem1, null); 

子视图在 方法中 GetChildView 设置,如下所示:

C#
view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleExpandableListItem2, null); 

然后,可以通过引用标准标识符和控件标识符来设置组视图和子视图 Text1 Text2 的属性,如上所示。 上面显示的 SimpleExpandableListItem (屏幕截图) 提供了单行组视图 (SimpleExpandableListItem1) 和双行子视图 (SimpleExpandableListItem2) 的示例。 或者,可以针对两行配置组视图 (SimpleExpandableListItem2) ,也可以为一行配置子视图 (SimpleExpandableListItem1) ,或者组视图和子视图可以具有相同的行数。

Accessories

行可以在视图右侧添加访问器以指示选择状态:

  • SimpleListItemChecked – 创建一个单选列表,以检查作为指示器。

  • SimpleListItemSingleChoice – 创建单选按钮类型列表,其中只能有一种选择。

  • SimpleListItemMultipleChoice – 创建可能有多个选项的复选框类型列表。

以下屏幕按其各自的顺序演示了上述附件:

具有附件的 SimpleListItemChecked、SimpleListItemSingleChoice 和 SimpleListItemMultipleChoice 的屏幕截图。

若要显示其中一个访问器,将所需的布局资源 ID 传递给适配器,然后手动设置所需行的选择状态。 此代码行演示如何使用以下布局 Adapter 之一创建和分配 :

C#
ListAdapter = new ArrayAdapter<String>(this, Android.Resource.Layout.SimpleListItemChecked, items); 

ListView本身支持不同的选择模式,而不考虑显示的附件。 为避免混淆,请 Single 对附件使用选择 SingleChoice 模式,将 CheckedMultiple 模式与 MultipleChoice 样式一起使用。 选择模式由 的 ChoiceMode 属性控制 ListView

处理 API 级别

早期版本的 Xamarin.Android 将枚举实现为整数属性。 最新版本引入了适当的 .NET 枚举类型,因此可以更轻松地发现潜在选项。

根据所面向的 API 级别, ChoiceMode 是整数或枚举。 如果要以"管理程序"API 为目标,示例文件 AccessoryViews/HomeScreen.cs 有一个注释掉的块:

C#
// For targeting Gingerbread the ChoiceMode is an int, otherwise it is an // enumeration. lv.ChoiceMode = Android.Widget.ChoiceMode.Single; // 1 //lv.ChoiceMode = Android.Widget.ChoiceMode.Multiple; // 2 //lv.ChoiceMode = Android.Widget.ChoiceMode.None; // 0 // Use this block if targeting Gingerbread or lower /*
lv.ChoiceMode = 1; // Single
//lv.ChoiceMode = 0; // none
//lv.ChoiceMode = 2; // Multiple
//lv.ChoiceMode = 3; // MultipleModal
*/ 

以编程方式选择项

手动设置哪些项"已选择"是使用 方法 (可以多次调用它以 SetItemChecked 执行多个选择) :

C#
// Set the initially checked row ("Fruits") lv.SetItemChecked(1, true); 

代码还需要以不同于多个选择的方式检测单个选择。 若要确定在模式下选择了哪一 Single 行,请使用 CheckedItemPosition integer 属性:

C#
FindViewById<ListView>(Android.Resource.Id.List).CheckedItemPosition 

若要确定在 模式下选择了哪些 Multiple 行,需要循环访问 CheckedItemPositions SparseBooleanArray 。 稀疏数组与仅包含值已更改的条目的字典类似,因此必须遍历整个数组以查找值,了解列表中选择的内容,如以下 true 代码片段所示:

C#
var sparseArray = FindViewById<ListView>(Android.Resource.Id.List).CheckedItemPositions; for (var i = 0; i < sparseArray.Size(); i++ )
{
   Console.Write(sparseArray.KeyAt(i) + "=" + sparseArray.ValueAt(i) + ",");
}
Console.WriteLine(); 

创建自定义行布局

这四个内置行视图非常简单。 若要显示更复杂的布局 (如电子邮件列表、推文或联系人信息) 自定义视图。 自定义视图通常声明为 Resources/Layout 目录中的 AXML 文件,然后通过自定义适配器使用其资源 ID 进行加载。 该视图可以包含任意数目的显示类 (如 TextViews、ImageViews 和其他控件) 自定义颜色、字体和布局。

此示例在很多方面与前面的示例不同:

  • 继承自 Activity ,而不是 ListActivity 。 可以自定义任何 的行,但也可以将其他控件包含在布局中 (如标题、按钮或其他用户界面元素 ListView Activity) 。 此示例在 上方添加标题 ListView 以说明。

  • 需要屏幕的 AXML 布局文件;在上一示例中, ListActivity 不需要布局文件。 此 AXML 包含 ListView 控件声明。

  • 需要 AXML 布局文件来呈现每一行。 此 AXML 文件包含具有自定义字体和颜色设置的文本和图像控件。

  • 使用可选的自定义选择器 XML 文件设置选定行的外观。

  • 实现 Adapter 从 重写返回自定义 GetView 布局。

  • ItemClick 如果事件处理程序 (,则必须以不同方式声明 ,而不是在 ListView.ItemClick OnListItemClick ListActivity) 。

下面详细介绍了这些更改,首先创建活动的视图和自定义行视图,然后介绍对适配器和活动的修改以呈现这些更改。

将 ListView 添加到活动布局

由于不再继承自 它没有默认视图,因此必须为 HomeScreen 视图创建布局 HomeScreen ListActivity AXML 文件。 对于此示例,视图将具有一个标题 (使用) 和 来 TextView ListView 显示数据。 布局在 Resources/Layout/HomeScreen.axml 文件中定义,如下所示:

XML
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/Heading" android:text="Vegetable Groups" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#00000000" android:textSize="30dp" android:textColor="#FF267F00" android:textStyle="bold" android:padding="5dp" /> <ListView android:id="@+id/List" android:layout_width="fill_parent" android:layout_height="fill_parent" android:cacheColorHint="#FFDAFF7F" /> </LinearLayout> 

将 与自定义布局控件 (而不是) 的好处在于能够向屏幕添加其他控件,如本示例 Activity ListActivity TextView 中的标题。

创建自定义行布局

需要另一个 AXML 布局文件来包含将在列表视图中显示的每一行的自定义布局。 此示例中,该行将具有绿色背景、棕色文本和右对齐图像。 Resources/Layout/CustomView.axml 中介绍了用于声明此布局的 Android XML 标记:

XML
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#FFDAFF7F" android:padding="8dp"> <LinearLayout android:id="@+id/Text" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dip"> <TextView android:id="@+id/Text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FF7F3300" android:textSize="20dip" android:textStyle="italic" /> <TextView android:id="@+id/Text2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14dip" android:textColor="#FF267F00" android:paddingLeft="100dip" /> </LinearLayout> <ImageView android:id="@+id/Image" android:layout_width="48dp" android:layout_height="48dp" android:padding="5dp" android:src="@drawable/icon" android:layout_alignParentRight="true" /> </RelativeLayout > 

虽然自定义行布局可以包含许多不同的控件,但滚动性能可能会受到复杂设计和使用图像的影响 (尤其是在必须通过网络连接加载图像时) 。 有关解决滚动性能问题的信息,请参阅 Google 的文章。

引用自定义行视图

自定义适配器示例的实现位于 HomeScreenAdapter.cs 中。 关键方法是使用资源 ID 加载自定义 AXML,然后在返回视图之前设置视图中每个控件 GetView Resource.Layout.CustomView 的属性。 将显示完整的适配器类:

C#
public class HomeScreenAdapter : BaseAdapter<TableItem> {
   List<TableItem> items;
   Activity context; public HomeScreenAdapter(Activity context, List<TableItem> items)
       : base() { this.context = context; this.items = items;
   } public override long GetItemId(int position) { return position;
   } public override TableItem this[int position]
   { get { return items[position]; }
   } public override int Count
   { get { return items.Count; }
   } public override View GetView(int position, View convertView, ViewGroup parent) { var item = items[position];
       View view = convertView; if (view == null) // no view to re-use, create new view = context.LayoutInflater.Inflate(Resource.Layout.CustomView, null);
       view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
       view.FindViewById<TextView>(Resource.Id.Text2).Text = item.SubHeading;
       view.FindViewById<ImageView>(Resource.Id.Image).SetImageResource(item.ImageResourceId); return view;
   }
} 

在活动中引用自定义 ListView

由于 类现在继承自 ,因此类中声明了一个字段,以保存对 HomeScreen Activity ListView AXML 中声明的控件的引用:

C#
ListView listView; 

然后, 类必须使用 方法加载活动的自定义布局 SetContentView AXML。 然后,它可以 ListView 在布局中查找控件,然后创建并分配适配器并分配单击处理程序。 OnCreate 方法的代码如下所示:

C#
SetContentView(Resource.Layout.HomeScreen); // loads the HomeScreen.axml as this activity's view listView = FindViewById<ListView>(Resource.Id.List); // get reference to the ListView in the layout // populate the listview with data listView.Adapter = new HomeScreenAdapter(this, tableItems);
listView.ItemClick += OnListItemClick; // to be defined 

最后 ItemClick ,必须定义处理程序;在这种情况下,它只显示一 Toast 条消息:

C#
void OnListItemClick(object sender, AdapterView.ItemClickEventArgs e) { var listView = sender as ListView; var t = tableItems[e.Position];
   Android.Widget.Toast.MakeText(this, t.Heading, Android.Widget.ToastLength.Short).Show();
} 

生成的屏幕如下所示:

生成的 CustomRowView 的屏幕截图。

自定义行选择器颜色

当接触行时,应突出显示该行,供用户反馈。 当自定义视图将 指定为 CustomView.axml 的背景色时,它还会替代选择突出显示。 CustomView.axml 中的这一行代码将背景设置为浅绿色,但这也意味着触摸该行时没有可视指示器:

XML
android:background="#FFDAFF7F" 

若要重新启用突出显示行为以及自定义所使用的颜色,请改为将背景属性设置为自定义选择器。 选择器将声明默认背景色和突出显示颜色。 文件 Resources/Drawable/CustomSelector.xml 包含以下声明:

XML
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="false" android:state_selected="false" android:drawable="@color/cellback" /> <item android:state_pressed="true" > <shape> <gradient android:startColor="#E77A26" android:endColor="#E77A26" android:angle="270" /> </shape> </item> <item android:state_selected="true" android:state_pressed="false" android:drawable="@color/cellback" /> </selector> 

若要引用自定义选择器,请更改 CustomView.axml 中的 background 属性,以:

XML
android:background="@drawable/CustomSelector" 

所选行和相应的 Toast 消息现在如下所示:

以橙色表示的选定行,其中 Toast 消息显示所选行的名称。

防止在自定义布局上闪烁

Android 尝试通过缓存布局 ListView 信息来提高滚动性能。 如果具有长滚动数据列表,则还应将活动 AXML 定义 (中的声明上的 属性设置为与自定义行布局的背景值相同的颜色 android:cacheColorHint ListView) 。 如果未能包含此提示,则用户滚动到具有自定义行背景色的列表时,可能会导致"闪烁"。