zoukankan      html  css  js  c++  java
  • 【Android】9.3 自定义列表视图的外观

    分类:C#、Android、VS2015;

    创建日期:2016-02-18

    一、简介

    自定义的列表视图通常用Resources/Layout文件夹下的axml文件中的资源来声明,适配器则通过Id去加载它。一个视图可以包含任意数量的类 (如 TextViews、 ImageViews 和其他控件) 以及自定义的颜色、字体和布局。

    由于ListView的外观是由行的布局决定的,因此,若要更改列表视图的外观,只需要使用不同的行布局即可。

    如果希望显示更复杂的布局 (如电子邮件、联系人列表),必须用自定义视图来实现。

    二、运行截图

    image  image

    三、主要设计步骤

    1、在colors.xml中添加颜色定义

    在/Resources/values/ colors.xml文件中添加本示例选中行的颜色:

    <color name="cellback">#FFDAFF7F</color>

    2、添加ch0902CustomSelector.xml文件

    在 /Resources/Drawable文件夹下添加该文件。

    <?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>

    3、添加ch0902_CustomView.axml文件

    要为列表视图中每一行都创建一个自定义的布局,必须定义一个单独的布局文件。在此示例中,每行都用绿色背景、棕色文本以及一个右对齐的图像来呈现。这个单独的布局保存在/Resources/Layout/ch0902_CustomView.axml文件中:

    <?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="@drawable/ch0902CustomSelector"
        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>

    虽然自定义行布局可以包含许多不同的控件,但是滚动性能可能会受到影响(特别是通过网络加载图像时)。

    关于解决滚动性能问题的详细信息,可参考谷歌官网上的相关文章。

    4、添加ch0902_Main.axml文件

    在/Resources/Layout文件夹下添加该文件。

    <?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: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>

    5、添加ch0902MyBaseAdapter.cs文件

    这个文件的关键是GetView方法,该方法使用Resource.Layout.ch0902_CustomView的资源ID加载自定义的axml,然后设置视图中控件的每个属性,最后返回结果。

    using System.Collections.Generic;
    using Android.App;
    using Android.Views;
    using Android.Widget;
    
    namespace MyDemos.SrcDemos
    {
        public class ch0902MyBaseAdapter : BaseAdapter<ch0901TableItem>
        {
            List<ch0901TableItem> items;
            Activity context;
            public ch0902MyBaseAdapter(Activity context, List<ch0901TableItem> items)
            {
                this.context = context;
                this.items = items;
            }
    
            public override long GetItemId(int position)
            {
                return position;
            }
    
            public override ch0901TableItem 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;
                // 如果没有可复用的视图(view为null),就创建一个新视图
                if (view == null)
                {
                    view = context.LayoutInflater.Inflate(Resource.Layout.ch0902_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;
            }
        }
    }

    6、添加ch0902Main.cs文件

    在SrcDemos文件夹下添加该文件。

    using System.Collections.Generic;
    using Android.App;
    using Android.OS;
    using Android.Widget;
    
    namespace MyDemos.SrcDemos
    {
        [Activity(Label = "【例9-2】 自定义视图")]
        public class ch0902Main : Activity
        {
            List<ch0901TableItem> tableItems = new List<ch0901TableItem>();
            ListView listView;
    
            protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
                SetContentView(Resource.Layout.ch0902_Main);
                listView = FindViewById<ListView>(Resource.Id.List);
                tableItems.Add(new ch0901TableItem() { Heading = "Vegetables", SubHeading = "65 items", ImageResourceId = Resource.Drawable.ch09Vegetables });
                tableItems.Add(new ch0901TableItem() { Heading = "Fruits", SubHeading = "17 items", ImageResourceId = Resource.Drawable.ch09Fruits });
                tableItems.Add(new ch0901TableItem() { Heading = "Flower Buds", SubHeading = "5 items", ImageResourceId = Resource.Drawable.ch09FlowerBuds });
                tableItems.Add(new ch0901TableItem() { Heading = "Legumes", SubHeading = "33 items", ImageResourceId = Resource.Drawable.ch09Legumes });
                tableItems.Add(new ch0901TableItem() { Heading = "Bulbs", SubHeading = "18 items", ImageResourceId = Resource.Drawable.ch09Bulbs });
                tableItems.Add(new ch0901TableItem() { Heading = "Tubers", SubHeading = "43 items", ImageResourceId = Resource.Drawable.ch09Tubers });
                listView.Adapter = new ch0902MyBaseAdapter(this, tableItems);
            }
        }
    }

    四、代码解释

    1、行复用

    如果所有行可在一个屏幕内全部显示出来,此时不需要复用。但是,当显示成百上千行的数据时,一次创建这么多的视图但只能使用几行太浪费内存空间了。为了避免这种情况,当某行从屏幕上消失时,可将其保存到一个队列中,以便复用。

    具体实现办法是:当用户滚动屏幕时,先判断在convertView参数中传递的视图实例,如果该值为null,就创建新的视图实例,否则重新设置该对象的属性以便复用它。

    GetView方法应该按下面的模式来复用行视图:

    public override View GetView(int position, View convertView, ViewGroup parent)

    {

           View view = convertView; // re-use an existing view, if one is supplied

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

           view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = items[position];

           return view;

    }

    创建新的视图前,自定义适配器应该总是实现convertView对象,这样可确保显示大量的列表数据时不会导致内存溢出。

    注意,某些适配器的实现(例如CursorAdapter)可能没有GetView方法,不过,这些适配器采用的策略是将GetView的职责分成两种不同的方法NewView和BindView,从而确保强制执行复用的行。

    2、快速滚动

    当一个ListView包含多行数据时,可利用快速滚动导航到该列表的不同部分(Api 11及更高版本都支持快速滚动)。

    将FastScrollEnabled属性设置为true,即可显示快速滚动手柄(handle):

            ListView.FastScrollEnabled = true;

    3、通过C#代码设置或查找选项

    设置列表中的初始化选项时,用SetItemChecked方法实现即可,例如:

           listview.SetItemChecked(1, true);

    也可能需要从多个选项中查找某个已选择的单项,例如:

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

    要确定在多选模式中用户选择了哪些行,需要遍历用稀疏数组(sparseArray)保存的所有可选项,该数组类似于一个保存更改记录的字典,所以必须遍历整个数组才能找到所有选项,例如:

    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();

    4、自定义所选行的颜色

    当用户选择某行时,一般应突出显示该行。突出显示行是在ch0902_CustomView.axml文件中实现的(将背景设置为淡绿色),重启突出显示的行也是用它来实现,但是采用的是反色背景。因此,先在 /Resources/Drawable/ch0902CustomSelector.xml 文件中包含对应的声明,然后在ch0902_CustomView.axml 文件中通过引用自定义的选择器来改变背景:

    android:background="@drawable/ch0902CustomSelector"

    当选择某行时(按住不抬起来),即得到运行截图所示的效果。

    5、避免滚动闪烁

    安卓系统是通过缓存布局信息来改善ListView的滚动性能的。如果列表视图中有比较长的滚动列表的数据,还应该在axml布局文件的ListView控件中声明android:cacheColorHint属性(将其值设置为和自定义行布局中的背景色相同),否则的话,滚动列表时就可能会出现一闪一闪(flicker)的情况。

  • 相关阅读:
    封装

    如何通过命令行窗口查看sqlite数据库文件
    标签控件
    信息提示框
    循环
    数组
    switch
    成员局部变量
    变量
  • 原文地址:https://www.cnblogs.com/rainmj/p/5197022.html
Copyright © 2011-2022 走看看