当前位置: 移动技术网 > 移动技术>移动开发>Android > 最常用和最难用的Android控件ListView

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

2019年07月24日  | 移动技术网移动技术  | 我要评论

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就占据了整个布局的空间.


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和数据之间的关联就建立完成了.


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

最终效果图:

5. 总结

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

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网