最常用和最难用的Android控件ListView
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.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
最常用和最难用的Android控件ListView
-
最常用和最难用的Android控件ListView
-
Android使用自定义控件HorizontalScrollView打造史上最简单的侧滑菜单
-
Android使用自定义控件HorizontalScrollView打造史上最简单的侧滑菜单
-
Android ListView列表控件的介绍和性能优化
-
Android最简单的限制输入方法(只包含数字、字母和符号)
-
android ListView和ProgressBar(进度条控件)的使用方法
-
Android ListView列表控件的介绍和性能优化
-
Android实现ListView控件的多选和全选功能实例
-
Android最常用和最难用的控件--ListView