如果你去做任何一个项目,我相信你都会跟我有一样的经历,最最普遍的就是列表显示ListView,当然,写N个自定义的适配器也是情理之中。虽说程序员本身就是搬砖,做这些枯燥无味的重复的事情也是理所当然,但不得不说,谁都想做点高效率的事情的。 而我们一向写的自定义适配器,无非就是继承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 list;20 21 public MyListAdapter(Context context, List list) {22 this.context = context;23 this.list = list;24 }25 26 @Override27 public int getCount() {28 return list == null ? 0 : list.size();29 }30 31 @Override32 public Object getItem(int position) {33 return list.get(position);34 }35 36 @Override37 public long getItemId(int position) {38 return position;39 }40 41 @Override42 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
好像没什么不对,但是这也没解决多少问题呀,要是我们在写大项目的时候还可以抽点时间出来打LOL拿个首胜什么的就更好了。 再来看看getView方法,基本都是先判断ViewHolder是否为空,为空则去Inflate一个xml文件进来,再绑定下视图,设置一个标记,不为空的时候直接引用标记。 或许这里我们可以试一下在ViewHolder上做点什么。 我们要是想把ViewHolder提取出来,只能把每一个Item都固定在ViewHolder里面,而Item又不是固定的,怎么办? 要是我们可以把这个Item直接作为参数传进来就好了,可是传控件好像不能区分,仔细一想,我们能看到一个控件对应着一个id,这个好像可以用HashMap的键值对处理。 而键值由于是Int型的,在新的java API中明确表示在键值为Integer的HashMap中我们要用SparseArray作代替,这样不仅简单,而且性能更优。 我们尝试着封装一下ViewHolder 1 public class ViewHolder { 2 //现在对于int作为键的官方推荐用SparseArray替代HashMap 3 private final SparseArray 这样的话我们的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 * 万能适配器的ViewHolder16 * Created by 南尘 on 16-7-28.17 */18 public class ViewHolder {19 //现在对于int作为键的官方推荐用SparseArray替代HashMap20 private final SparseArray 上面的图片网络加载我用Picasso加载框架,这个网上很多图片加载框架,我前面博客也有很多Demo,大家可以自行查找。 再看看我们的万能适配器,这里我们把它写做一个抽象类,传入一个泛型作为参数。 1 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 再看看我们主页面怎么调用的。 1 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 list;14 15 @Override16 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(this,list) {24 @Override25 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;="">) {39 list.add(new Data('本地 '+i,R.mipmap.ic_launcher));40 }41 42 for (int i = 0; i < 5;="">) {43 list.add(new Data('网络 '+i,'http://pic.cnblogs.com/face/845964/20160301162812.png'));44 }45 }46 } 最后上我写的两个xml 一个是Activity_main.xml 1 2 RelativeLayout 3 xmlns:android='http://schemas./apk/res/android' 4 xmlns:tools='http://schemas./tools' 5 android:layout_width='match_parent' 6 android:layout_height='match_parent' 7 tools:context='com.example.nanchen.commonadapterforlistviewdemo.MainActivity'> 8 9 10 ListView11 android:layout_width='match_parent'12 android:layout_height='match_parent'13 android:id='@+id/main_lv'/>14 list_item.xml 这个你想怎么定义就想定义了。 本人亲测这个东西可以用,还没入坑的小伙伴赶快入坑吧。 明天我可能还会带来万能的RecyclerView的适配器,还请大家持续关注~~~~
———————————————————————————————————————————————————————————————————————————— 7月30日补充: 今天在自己思考写最近大火的RecyclerView的万能适配器的时候参考这边的时候,发现在MainActivity中竟然不能设置其他的布局,才发现自己之前的逻辑有点问题,应该把Layout的ID也作为参数传到Adater去中。看来自己有时候想的也不是很周到,大家看的时候也要多加思考呀。 这是改动后的Adpter和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 9 import java.util.List;10 11 /**12 * 打造ListView的万能适配器13 * Created by 南尘 on 16-7-28.14 */15 public abstract class CommonAdaper 思想里面应该很清楚了吧。 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 * 万能适配器的ViewHolder16 * Created by 南尘 on 16-7-28.17 */18 public class ViewHolder {19 //现在对于int作为键的官方推荐用SparseArray替代HashMap20 private final SparseArray 同步重新同步至Github:https://github.com/nanchen2251/CommonAdapterListViewDemo |
|