天天看点

Android ListView 详解

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还没那么简单,这些可能会在后面的博客中说道,希望这篇博客对大家有所帮助,谢谢!

继续阅读