ListVie 在android开发中w是非常重要的控件。我自己也还是一个小白,把自己的学习经验分享出来,希望可以帮到初学Android的朋友们。这也是我第一次写博客,我尽量将结构处理的好一些,也说的易懂一些。如果写得不好或者有误,请指正见谅!
简介
批量展示结构一样或者相似的信息并且可以滑动展示。ListView是一个组合控件,组合控件和普通控件的区别在于:
普通控件:内容和控件是一起的。
组合控件:内容跟控件是分开的。
所以使用ListView的时候要用到适配器,那什么是适配器呢,官方文档的解释是控件与数据之间的一个桥梁。如果不好理解,不要纠结,用多了自然就明白了。ListView作为一个整体的框架,而适配器则决定每一行上的内容是什么:
ListView 框架
适配器 内容
使用
简单介绍过ListView之后,我们来说下ListView的使用。
1、在Activity的布局文件中放入Listview。注意: listview的高度要是 match_parent 或者是固定值。如果设置为wrapcontent则会有requestLayout 的操作对性能损耗较大。
2、准备好listview的行布局文件listview_item,作为listview每一行的显示样式。
3、准备listview的适配器
声明一个类继承BaseAdpater,实现四个方法:
public int getCount() //这个方法决定了listview显示内容的行数
//决定listview每一行的布局以及内容,注意:listview上的每一行要显示在界面上都必须调用getView(),每一个已经消失在屏幕上的行,重新显示在界面都必须重新调用get //View()。position这个参数代表是listview上面的行号。注意:如果getCount() 返回的结果为0的话,是不会调用getView()
public View getView(int position, View convertView, ViewGroup parent)
4、getView()中每一行的布局创建以及内容设置
LayoutInflater inflater = getLayoutInflater();//得到布局转换器
TextView textView =(TextView)layout.findViewById(R.id.tv_list_item);
//通过行号查找容器里面对应的内容
textView.setText(string);
//返回行布局对象(而不是里面某个控件)
ListView listView = (ListView) findViewById(R.id.listView1);
MyAdapter adapter = new MyAdapter();
5、查找Listview控件对象
ListView listView = (ListView) findViewById(R.id.listView1);
6、创建一个适配器对象
MyAdapter adapter = new MyAdapter();
7、为listview配置适配器(如果没有配置,listview里面是没有内容的)
listView.setAdapter(adapter);
这里再说明一下,行布局为多个控件,就是之前创建的listview_item,每一行都是listview_item。还要注意的是每一个控件的索引都必须通过行布局对象去查找。(否则就为null,运行时会报空指针异常)。
优化
讲完ListView的使用后,讲一下ListView的优化。
1、复用行布局
getView()的时候都创建一个新的行布局对象,又因为Android的垃圾回收机制是不定时回收的,当数据比较多的时候,你上下滑动,ListView就不断的创建对象,轻则会造成卡顿,重则就内存溢出了。其实我们知道,如果屏幕上可以显示6行,我们准备7个布局对象就可以。如果不明白的童鞋可以想象一下,就像戏台上演行军并不需要那么多人,只要让前面走出戏台的人再从后面接上来就可以了。
复用行布局:
public View getView(int position, View convertView, ViewGroup parent) {
View layout = null;
if(convertView == null)
{
LayoutInflater inflater = getLayoutInflater();//得到布局转换器
layout = inflater.inflate(R.layout.list_item, null);
}else
{
layout = convertView;
}
return layout;
}
convertView: 用来保存已经创建并且消失在界面的那个行布局对象的索引。初始为null,当行布局对象消失的时候才有值。
2、减少查找次数
基于复用行布局的基础上,如果每一次getView(),都要再去找行布局上的控件也是很麻烦的,因为既然是复用,之前肯定是已经找过了。这里的优化方法如下:
class ViewHolder{
ImageView imageView;
TextView title;
TextView subTitle;
}
在getVIew中
public View getView(int position, View convertView, ViewGroup parent) {
View layout = null;
ViewHolder holder = null;
if(convertView == null)
{
holder = new ViewHolder();
LayoutInflater inflater = getLayoutInflater();//得到布局转换器
layout = inflater.inflate(R.layout.list_item, null);
holder.imageView = (ImageView) layout.findViewById(R.id.iv_list);
holder.title = (TextView) layout.findViewById(R.id.tv_list_item);
holder.subTitle = (TextView) layout.findViewById(R.id.tv_list_sub);
//标签(口袋)
layout.setTag(holder);
}else
{
layout = convertView;
holder = (ViewHolder) layout.getTag();
}
当然ListView的优化在实际的项目开发中在数据请求的过程中会有一些bug,这里以后再说明解决。
数据更新
adapter.notifyDataSetChanged();
lisetview 行点击事件
1、点击
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View view,
Log.e("onItemClick", "position:" + position);
});
2、长按弹出选项菜单
registerForContextMenu(listView);
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView parent, View view,
return false; (返回false的时候事件还会向下传递,返回true就到此结束)
});
当然还需重写onCreateContextMenu和onContextItemSelected方法。listvew
listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
// @Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {}
});
注意: 当行布局中有可以抢占焦点的控件的时候,行布局的焦点会被抢占所以不能点击
解决:
1、设置抢占焦点的控件的属性
android:focusable="false"
2、如果行布局中有多个抢占焦点的控件,可以在行布局文件的布局容器中设置:
android:descendantFocusability="blocksDescendants
总结
好了,ListView就讲到这里了,当然要做出漂亮的listview还没那么简单,这些可能会在后面的博客中说道,希望这篇博客对大家有所帮助,谢谢!