欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

最常用和最难用的Android控件ListView

程序员文章站 2024-03-04 14:40:53
listview允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕. 1. listview的简单用法 首先新建一个listv...

listview允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕.

1. listview的简单用法
首先新建一个listviewtest项目,然后修改activity_main.xml代码.

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_height="match_parent" 
  android:layout_width="match_parent">
 <listview 
  android:id="@+id/list_view"
  android:layout_width="match_parent"
  android:layout_height="match_parent"></listview>
</linearlayout>

为listview指定一个id,然后将宽度和高度都修改为match_parent,这样listview就占据了整个布局的空间.

最常用和最难用的Android控件ListView

listview布局

接下来修改mainactivity中的代码.

public class mainactivity extends activity {
 private string[] data = {"apple","banana","orange","watermelon",
   "pear","grape","pineapple","strawberry","cherry","mango"};
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);
  //先创建适配器,并且把内容放入去.
  arrayadapter<string> adapter = new arrayadapter<string>
  (mainactivity.this, android.r.layout.simple_list_item_1,data);
  listview listview = (listview) findviewbyid(r.id.list_view);
  //调用listview的对象把适配器传进去.
  listview.setadapter(adapter);
 }


}

数组中的数据是无法直接传递给listview的,我们需要借助适配器来完成,其中最好用的是arrayadapter它可以通过泛型来指定要添加的数据类型,然后在构造函数中把要适配的数据传入即可.注意我们使用了android.r.layout.simple_list_item_1作为listview的子项布局的id,以及要适配的数据.

最后,我们要调用listview的setadapter()方法,将构造好的适配器对象传递进去,这样listview和数据之间的关联就建立完成了.

最常用和最难用的Android控件ListView

listview与数据关联

2. 定制listview的界面
接着定义一个实体类,作为listview适配器的适配类型,新建类fruit,需要准备一组图片.

public class fruit {

 private string name;

 private int imageid;

 public fruit(string name, int imageid) {
  this.name = name;
  this.imageid = imageid;
 }

 public string getname() {
  return name;
 }

 public int getimageid() {
  return imageid;
 }

}

fruit类中只有两个字段,name表示水果的名字,imageid表示水果对应图片的资源id.

然后需要为listview的子项指定一个我们自定义的布局,在layout目录下新建fruit_item.xml

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent" >

 <imageview
  android:id="@+id/fruit_image"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />

 <textview
  android:id="@+id/fruit_name"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="center"
  android:layout_marginleft="10dip" />

</linearlayout>

在这个布局里,我们定义了一个imageview用于显示水果的图片,又定义了一个textview用于显示水果的名称.

接下来需要创建一个自定义的适配器,这个适配器继承自arrayadapter,并将泛型指定为fruit类.新建类fruitadapter,代码如下:

public class fruitadapter extends arrayadapter<fruit> {

 private int resourceid;

 public fruitadapter(context context, int textviewresourceid,
   list<fruit> objects) {
  super(context, textviewresourceid, objects);
  resourceid = textviewresourceid;
 }

 @override
 public view getview(int position, view convertview, viewgroup parent) {
  fruit fruit = getitem(position);
  view view = layoutinflater.from(getcontext()).inflate(resourceid, null);
  imageview fruitimage = (imageview) view.findviewbyid(r.id.fruit_image);
  textview fruitname = (textview) view.findviewbyid(r.id.fruit_name);
  fruitimage.setimageresource(fruit.getimageid()); 
  fruitname.settext(fruit.getname());
  return view;
 }

}

fruitadapter重写了父类的一组构造函数,用于将上下文,listview子项布局的id和数据都传递进来.另外又重写了getview()方法,首先通过getitem()方法得到当前项的fruit的实例,然后使用layoutinflater来为这个子项加载我们传入的布局,接着调用view的fndviewbyid()方法分别获取到imageview和textview的实例,并分别调用它们的setimageresource和settext方法来设置显示的图片和文字,最好将布局返回.

下面修改mainactivity中的代码,如下所示:

public class mainactivity extends activity {

 private list<fruit> fruitlist = new arraylist<fruit>();

 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);
  initfruits();
  fruitadapter adapter = new fruitadapter(mainactivity.this,
    r.layout.fruit_item, fruitlist);
  listview listview = (listview) findviewbyid(r.id.list_view);
  listview.setadapter(adapter);

 }

 private void initfruits() {
  fruit apple = new fruit("apple", r.drawable.apple_pic);
  fruitlist.add(apple);
  fruit banana = new fruit("banana", r.drawable.banana_pic);
  fruitlist.add(banana);
  fruit orange = new fruit("orange", r.drawable.orange_pic);
  fruitlist.add(orange);
  fruit watermelon = new fruit("watermelon", r.drawable.watermelon_pic);
  fruitlist.add(watermelon);
  fruit pear = new fruit("pear", r.drawable.pear_pic);
  fruitlist.add(pear);
  fruit grape = new fruit("grape", r.drawable.grape_pic);
  fruitlist.add(grape);
  fruit pineapple = new fruit("pineapple", r.drawable.pineapple_pic);
  fruitlist.add(pineapple);
  fruit strawberry = new fruit("strawberry", r.drawable.strawberry_pic);
  fruitlist.add(strawberry);
  fruit cherry = new fruit("cherry", r.drawable.cherry_pic);
  fruitlist.add(cherry);
  fruit mango = new fruit("mango", r.drawable.mango_pic);
  fruitlist.add(mango);
 }

}

可以看到,这里添加了一个initfruits()方法,用于初始化所有水果的数据,在fruit类构造函数将水果的名字和对应图片id传入,然后把创建好的对象添加到水果列表中,接着我们再oncreate()方法中创建了fruitadapter对象,并将fruitadapter作为适配器传递给listview.

3. 提升listview的运行效率
因为在fruitadapter的getview()方法中每次都将布局重新加载了一次,当listview快速滚动的时候就会成为性能的阻碍.

public class fruitadapter extends arrayadapter<fruit> {

 private int resourceid;

 public fruitadapter(context context, int textviewresourceid,
   list<fruit> objects) {
  super(context, textviewresourceid, objects);
  resourceid = textviewresourceid;
 }

 @override
 public view getview(int position, view convertview, viewgroup parent) {
  fruit fruit = getitem(position); // 获取当前项的fruit实例
  view view;
  if (convertview == null) {
   view = layoutinflater.from(getcontext()).inflate(resourceid, null);
  } else {
   view = convertview;
  }
  imageview fruitimage = (imageview) view.findviewbyid(r.id.fruit_image);
  textview fruitname = (textview) view.findviewbyid(r.id.fruit_name);
  fruitimage.setimageresource(fruit.getimageid());
  fruitname.settext(fruit.getname());
  return view;
 }

}

所以,我们再getview()方法中进行了判断,如果convertview为空,则使用layoutinflater去加载布局,如果不为空则直接对convertview进行重用.

每次在getview()方法中还是会调用view的findviewbyid()方法来获取一次控件的实例,我们还可以借助一个viewholder来对这部分性能进行优化,修改fruitadapter`中的代码,如下所示:

public class fruitadapter extends arrayadapter<fruit> {

 private int resourceid;

 public fruitadapter(context context, int textviewresourceid,
   list<fruit> objects) {
  super(context, textviewresourceid, objects);
  resourceid = textviewresourceid;
 }

 @override
 public view getview(int position, view convertview, viewgroup parent) {
  fruit fruit = getitem(position);
  view view;
  viewholder viewholder;
  if (convertview == null) {
   view = layoutinflater.from(getcontext()).inflate(resourceid, null);
   viewholder = new viewholder();
   viewholder.fruitimage = (imageview) view.findviewbyid(r.id.fruit_image);
   viewholder.fruitname = (textview) view.findviewbyid(r.id.fruit_name);
   view.settag(viewholder);
  } else {
   view = convertview;
   viewholder = (viewholder) view.gettag();
  }
  viewholder.fruitimage.setimageresource(fruit.getimageid());
  viewholder.fruitname.settext(fruit.getname());
  return view;
 }

 class viewholder {

  imageview fruitimage;

  textview fruitname;

 }

}

我们新建了一个内部类viewholder,用于对控件的实例进行缓存.当convertview为空的时候,创建一个viewholder对象,并将控件的实例都存放在viewholder里,然后调用view的settag()方法,将viewholder对象存储在view中.当convertview不为空的时候则调用view的gettag()方法,把viewholder重新取出.这样所有控件的实例都缓存在viewholder里,就没有必要每次都通过findviewbyid()方法来获取控件实例了.

4. listview的点击事件

  listview.setonitemclicklistener(new onitemclicklistener() {
   @override
   public void onitemclick(adapterview<?> parent, view view,
     int position, long id) {
    fruit fruit = fruitlist.get(position);
    toast.maketext(mainactivity.this, fruit.getname(),
      toast.length_short).show();
   }
  });

最终效果图:

最常用和最难用的Android控件ListView

5. 总结

先在布局中加入listview控件
然后自定义适配器,这个适配器继承自arrayadapter
初始化数据,把数据传入自定义适配器
然后将适配器传递给listview.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。