Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

打造android偷懒神器———ListView的万能适配器

$
0
0

我们一向写的自定义适配器,无非就是继承ArrayAdapter,或者继承自BaseAdapter,然后重写4个方法,前三个方法基本相同,不同在于getView方法,getView里面为了减少绑定和View的重建,又会引入一个静态类ViewHolder,我相信下面这段代码你一点见过不少。


 1 package com.example.nanchen.commonadapterforlistviewdemo;
 2 
 3 import android.content.Context;
 4 import android.view.LayoutInflater;
 5 import android.view.View;
 6 import android.view.ViewGroup;
 7 import android.widget.BaseAdapter;
 8 import android.widget.ImageView;
 9 import android.widget.TextView;
10 
11 import java.util.List;
12 
13 /**
14  * 常见的ListView的Adapter适配器
15  * Created by 南尘 on 16-7-28.
16  */
17 public class MyListAdapter extends BaseAdapter {
18     private Context context;
19     private List<Data> list;
20 
21     public MyListAdapter(Context context, List<Data> list) {
22         this.context = context;
23         this.list = list;
24     }
25 
26     @Override
27     public int getCount() {
28         return list == null ? 0 : list.size();
29     }
30 
31     @Override
32     public Object getItem(int position) {
33         return list.get(position);
34     }
35 
36     @Override
37     public long getItemId(int position) {
38         return position;
39     }
40 
41     @Override
42     public View getView(int position, View convertView, ViewGroup viewGroup) {
43         MyViewHolder holder = null;
44         if (convertView == null) {
45             convertView = LayoutInflater.from(context).inflate(R.layout.list_item,viewGroup,false);
46             holder = new MyViewHolder();
47             holder.iv = (ImageView) convertView.findViewById(R.id.item_image);
48             holder.tv = (TextView) convertView.findViewById(R.id.item_text);
49             convertView.setTag(holder);
50         } else {
51             holder = (MyViewHolder) convertView.getTag();
52         }
53         Data data = (Data) getItem(position);
54         holder.iv.setImageResource(data.getImageId());
55         holder.tv.setText(data.getText());
56         return convertView;
57     }
58 
59     public static class MyViewHolder {
60         ImageView iv;
61         TextView tv;
62     }
63 }

上面是大家最常用,见到的适配器的写法,如果咱们项目中需要很多的适配器的话,咱们一个个写,想想就很浪费时间,因此咱们可以自己封装一个
仔细观察上面的Adapter,的确是前三个方法一样。我们要是可以全部抽出来就好了。所以可以抽出来,写一个泛型使其变成一个抽象的基类,继承自BaseAdapter.其子类只需要去关心其getView方法

1 public abstract class MyListAdapter<T> extends BaseAdapter {
 2     private Context context;
 3     private List<T> list;
 4 
 5     public MyListAdapter(Context context, List<T> list) {
 6         this.context = context;
 7         this.list = list;
 8     }
 9 
10     @Override
11     public int getCount() {
12         return list == null ? 0 : list.size();
13     }
14 
15     @Override
16     public Object getItem(int position) {
17         return list.get(position);
18     }
19 
20     @Override
21     public long getItemId(int position) {
22         return position;
23     }
24 }

好像没什么不对,但是这也没解决多少问题呀,要是我们在写大项目的时候还可以抽点时间出来打LOL拿个首胜什么的就更好了。
再来看看getView方法,基本都是先判断ViewHolder是否为空,为空则去Inflate一个xml文件进来,再绑定下视图,设置一个标记,不为空的时候直接引用标记。
或许这里我们可以试一下在ViewHolder上做点什么。
我们要是想把ViewHolder提取出来,只能把每一个Item都固定在ViewHolder里面,而Item又不是固定的,怎么办?
要是我们可以把这个Item直接作为参数传进来就好了,可是传控件好像不能区分,仔细一想,我们能看到一个控件对应着一个id,这个好像可以用HashMap的键值对处理。
而键值由于是Int型的,在新的java API中明确表示在键值为Integer的HashMap中我们要用SparseArray作代替,这样不仅简单,而且性能更优。
我们尝试着封装一下ViewHolder:

 public class ViewHolder {
 2     //现在对于int作为键的官方推荐用SparseArray替代HashMap
 3     private final SparseArray<View> views;
 4     private int position;
 5     private View convertView;
 6     private Context context;
 7 
 8     private ViewHolder(Context context,ViewGroup parent, int layoutId, int position) {
 9         this.context = context;
10         this.views = new SparseArray<>();
11         this.convertView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
12         convertView.setTag(this);
13     }
14 
15     /**
16      * 拿到一个ViewHolder对象
17      */
18     public static ViewHolder get(View convertView, ViewGroup parent, int layoutId, int position) {
19         if (convertView == null) {
20             return new ViewHolder(parent.getContext(),parent, layoutId, position);
21         }
22         return (ViewHolder) convertView.getTag();
23     }
24 
25     /**
26      * 通过控件的Id获取对于的控件,如果没有则加入views
27      */
28     public <T extends View> T getView(int viewId) {
29         View view = views.get(viewId);
30         if (view == null) {
31             view = convertView.findViewById(viewId);
32             views.put(viewId, view);
33         }
34         return (T) view;
35     }
36 }

这样的话我们的getView可能会变成这样。

1 @Override  
2     public View getView(int position, View convertView, ViewGroup parent){  
3         ViewHolder viewHolder = ViewHolder.get(convertView, parent,  
4                 R.layout.list_item, position);  
5         TextView mTitle = viewHolder.getView(R.id.id_tv_title);  
6         mTitle.setText(((Data) list.get(position)).getText());  
7         //这里就不设置ImageView了
8         return viewHolder.getConvertView();  
9     } 

好吧。与其这样。我们不如直接写在Activity中。
并且如果我们想设置东西也许可以在Holder里面设置,我们可以试一试。
封装后的ViewHolder是这样。

1 package com.example.nanchen.commonadapterforlistviewdemo;
 2 
 3 import android.content.Context;
 4 import android.graphics.Bitmap;
 5 import android.util.SparseArray;
 6 import android.view.LayoutInflater;
 7 import android.view.View;
 8 import android.view.ViewGroup;
 9 import android.widget.ImageView;
10 import android.widget.TextView;
11 
12 import com.squareup.picasso.Picasso;
13 
14 /**
15  * 万能适配器的ViewHolder
16  * Created by 南尘 on 16-7-28.
17  */
18 public class ViewHolder {
19     //现在对于int作为键的官方推荐用SparseArray替代HashMap
20     private final SparseArray<View> views;
21     private int position;
22     private View convertView;
23     private Context context;
24 
25     private ViewHolder(Context context,ViewGroup parent, int layoutId, int position) {
26         this.context = context;
27         this.views = new SparseArray<>();
28         this.convertView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
29         convertView.setTag(this);
30     }
31 
32     /**
33      * 拿到一个ViewHolder对象
34      */
35     public static ViewHolder get(View convertView, ViewGroup parent, int layoutId, int position) {
36         if (convertView == null) {
37             return new ViewHolder(parent.getContext(),parent, layoutId, position);
38         }
39         return (ViewHolder) convertView.getTag();
40     }
41 
42     /**
43      * 通过控件的Id获取对于的控件,如果没有则加入views
44      */
45     public <T extends View> T getView(int viewId) {
46         View view = views.get(viewId);
47         if (view == null) {
48             view = convertView.findViewById(viewId);
49             views.put(viewId, view);
50         }
51         return (T) view;
52     }
53 
54     public View getConvertView() {
55         return convertView;
56     }
57 
58     /**
59      * 设置字符串
60      */
61     public ViewHolder setText(int viewId,String text){
62         TextView tv = getView(viewId);
63         tv.setText(text);
64         return this;
65     }
66 
67     /**
68      * 设置图片
69      */
70     public ViewHolder setImageResource(int viewId,int drawableId){
71         ImageView iv = getView(viewId);
72         iv.setImageResource(drawableId);
73         return this;
74     }
75 
76     /**
77      * 设置图片
78      */
79     public ViewHolder setImageBitmap(int viewId, Bitmap bitmap){
80         ImageView iv = getView(viewId);
81         iv.setImageBitmap(bitmap);
82         return this;
83     }
84 
85     /**
86      * 设置图片
87      */
88     public ViewHolder setImageByUrl(int viewId,String url){
89         Picasso.with(context).load(url).into((ImageView) getView(viewId));
90 //        ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context));
91 //        ImageLoader.getInstance().displayImage(url, (ImageView) getView(viewId));
92         return this;
93     }
94 
95     public int getPosition(){
96         return position;
97     }
98 }

上面的图片网络加载我用Picasso加载框架,这个网上很多图片加载框架
再看看我们的万能适配器,这里我们把它写做一个抽象类,传入一个泛型作为参数。

package com.example.nanchen.commonadapterforlistviewdemo;
 2 
 3 import android.content.Context;
 4 import android.view.View;
 5 import android.view.ViewGroup;
 6 import android.widget.BaseAdapter;
 7 
 8 import java.util.List;
 9 
10 /**
11  * 打造ListView的万能适配器
12  * Created by 南尘 on 16-7-28.
13  */
14 public abstract class CommonAdaper<T> extends BaseAdapter {
15     private Context context;
16     private List<T> list;
17 
18 
19     public CommonAdaper(Context context, List<T> list) {
20         this.context = context;
21         this.list = list;
22     }
23 
24     @Override
25     public int getCount() {
26         return list == null ? 0 : list.size();
27     }
28 
29     @Override
30     public T getItem(int position) {
31         return list.get(position);
32     }
33 
34     @Override
35     public long getItemId(int position) {
36         return position;
37     }
38 
39     @Override
40     public View getView(int i, View view, ViewGroup viewGroup) {
41         ViewHolder holder = ViewHolder.get(view,viewGroup,R.layout.list_item,i);
42         convert(holder,getItem(i));
43         return holder.getConvertView();
44     }
45 
46     public abstract void convert(ViewHolder holder,T item);
47 
48 }

用法的话就更简单了

package com.example.nanchen.commonadapterforlistviewdemo;
 2 
 3 import android.support.v7.app.AppCompatActivity;
 4 import android.os.Bundle;
 5 import android.widget.ListView;
 6 
 7 import java.util.ArrayList;
 8 import java.util.List;
 9 
10 public class MainActivity extends AppCompatActivity {
11 
12     private ListView listView;
13     private List<Data> list;
14 
15     @Override
16     protected void onCreate(Bundle savedInstanceState) {
17         super.onCreate(savedInstanceState);
18         setContentView(R.layout.activity_main);
19 
20         listView = (ListView) findViewById(R.id.main_lv);
21         initList();
22 
23         listView.setAdapter(new CommonAdaper<Data>(this,list) {
24             @Override
25             public void convert(ViewHolder holder, Data item) {
26                 holder.setText(R.id.item_text,item.getText());
27                 if (item.getImageUrl() != null){
28                     holder.setImageByUrl(R.id.item_image,item.getImageUrl());
29                 }else {
30                     holder.setImageResource(R.id.item_image,item.getImageId());
31                 }
32             }
33         });
34     }
35 
36     private void initList() {
37         list = new ArrayList<>();
38         for (int i = 0; i < 5; i++) {
39             list.add(new Data("本地 "+i,R.mipmap.ic_launcher));
40         }
41 
42         for (int i = 0; i < 5; i++) {
43             list.add(new Data("网络 "+i,"http://pic.cnblogs.com/face/845964/20160301162812.png"));
44         }
45     }
46 }

itme的xml布局文件
一个是Activity_main.xml

 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     tools:context="com.example.nanchen.commonadapterforlistviewdemo.MainActivity">
 8 
 9 
10     <ListView
11         android:layout_width="match_parent"
12         android:layout_height="match_parent"
13         android:id="@+id/main_lv"/>
14 </RelativeLayout>

list_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="wrap_content"
              android:orientation="horizontal">

    <ImageView
        android:id="@+id/item_image"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:src="@mipmap/ic_launcher"/>


    <TextView
        android:id="@+id/item_text"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center"
        android:text="内容"/>

</LinearLayout>

完事,有问题留言交流~

作者:liwei123liwei123 发表于2016/10/10 10:48:19 原文链接
阅读:31 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles