android打造万能的适配器(转)
荒废了两天,今天与大家分享一个ListView的适配器
前段时间在学习慕课网的视频,觉得这种实现方式较好,便记录了下来,最近的项目中也使用了多次,节省了大量的代码,特此拿来与大家分享一下。
还是先看图片,这里我模仿博客园App的列表样式做了一个静态的数据列表
这里用到的类比较多,不过核心的只有两个,其余均为演示所用,先来看核心的两个类
ViewHolderM.java
package landptf.tools; import android.content.Context; import android.text.Spanned; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; /** * @author landptf * 公共的ViewHolder */ public class ViewHolderM { private SparseArray<View> viewArray; private int position; private View mConvertView; private Object tag; /** * 构造方法 * @param context * @param convertView * @param parent * @param layoutId * @param position */ public ViewHolderM(Context context, View convertView, ViewGroup parent, int layoutId, int position) { this.position = position; //使用SparseArray效率高一些 viewArray = new SparseArray<View>(); //加载布局 mConvertView = LayoutInflater.from(context).inflate(layoutId, parent,false); //将ViewHolderM赋值给View的Tag mConvertView.setTag(this); } public static ViewHolderM get(Context context, View convertView, ViewGroup parent, int layoutId, int position) { if (convertView == null) { //如果convertView为空,则实例化ViewHolderM return new ViewHolderM(context, convertView, parent, layoutId,position); } else { //否则从convertView的Tag中取出ViewHolderM,避免重复创建 ViewHolderM holder = (ViewHolderM) convertView.getTag(); holder.position = position; return holder; } } public View getConvertView() { return mConvertView; } public Object getTag() { return tag; } public void setTag(Object tag) { this.tag = tag; } public int getPosition() { return position; } public void setPosition(int position) { this.position = position; } /** * 通过viewId获取控件对象 * @param viewId * @return */ @SuppressWarnings("unchecked") public <T extends View> T getView(int viewId) { View view = viewArray.get(viewId); if (view == null) { view = mConvertView.findViewById(viewId); viewArray.put(viewId, view); } return (T) view; } /**------------------------------------华丽的分割线------------------------------------*/ /**以下方法为额外封装的方法,只是简单几个,以后可以慢慢完善*/ /** * 设置TextView的内容 * @param viewId * @param text * @return */ public ViewHolderM setText(int viewId, String text) { TextView tv = getView(viewId); tv.setText(text); return this; } /** * 设置TextView的内容 * @param viewId * @param text,Spanned类型,可设置部分字体变色 * @return */ public ViewHolderM setText(int viewId, Spanned text) { TextView tv = getView(viewId); tv.setText(text); return this; } /** * 设置图片的可见性 * @param viewId * @param visible * @return */ public ViewHolderM setImageViewVisible(int viewId, Boolean visible){ ImageView iv = getView(viewId); if (visible) { iv.setVisibility(View.VISIBLE); }else { iv.setVisibility(View.GONE); } return this; } }
2 AdapterM.java
package landptf.tools; import java.util.List; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; /** * @author landptf * 公共的Adapter List适配器 */ public abstract class AdapterM<T> extends BaseAdapter { private Context context; //为丰富程序功能,提供了两种常见的数据类型 private List<T> dataList = null;//数据源List<T> private T[] dataArray = null;//数据源T[] //布局文件ID private int layoutId; /** * 构造方法 * @param context * @param layoutId * @param dataList */ public AdapterM(Context context,int layoutId, List<T> dataList) { this.context = context; this.dataList = dataList; this.layoutId = layoutId; } /** * 构造方法(与上一个只有数据源不同) * @param context * @param layoutId * @param dataArray */ public AdapterM(Context context,int layoutId, T[] dataArray) { this.context = context; this.dataArray = dataArray; this.layoutId = layoutId; } @Override public int getCount() { if (dataList != null) { return dataList.size(); }else { return dataArray.length; } } @Override public T getItem(int position) { if (dataList != null) { return dataList.get(position); }else { return dataArray[position]; } } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolderM holder = new ViewHolderM(context, convertView, parent,layoutId, position); convert(holder,getItem(position)); return holder.getConvertView(); } /** * 需实现的抽象方法 * @param holder * @param model */ public abstract void convert(ViewHolderM holder, T model); }
接下来看布局文件,一共两个一个是activity的页面,一个列表项
activity_list.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#EFEFEF" > <include android:id="@+id/title" layout="@layout/child_titlebarm" /> <ListView android:id="@+id/lv_list" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/title" android:layout_marginTop="10dp" android:background="@android:color/white" android:divider="#A9A9A9" android:dividerHeight="1dp"> </ListView> </RelativeLayout>
item_messgae.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" tools:ignore="HardcodedText" > <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="10dp" android:maxLines="2" android:textColor="#696969" android:textSize="20sp" /> <TextView android:id="@+id/tv_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/tv_title" android:layout_below="@+id/tv_title" android:layout_marginRight="10dp" android:layout_marginTop="10dp" android:maxLines="3" android:textColor="#696969" android:textSize="16sp" /> <TextView android:id="@+id/tv_comment" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/tv_content" android:layout_below="@+id/tv_content" android:layout_marginTop="10dp" android:textColor="#696969" android:textSize="18sp" /> <TextView android:id="@+id/tv_read" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@+id/tv_comment" android:layout_centerHorizontal="true" android:textColor="#696969" android:textSize="18sp" /> <TextView android:id="@+id/tv_collect" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@+id/tv_read" android:layout_alignParentRight="true" android:layout_marginRight="10dp" android:text="立马收藏" android:textColor="#696969" android:textSize="18sp" /> </RelativeLayout>
接下来我们定义了一个Adapter类继承AdapterM,ListAdapter.java
package landptf.test; import landptf.control.R; import android.content.Context; import landptf.tools.AdapterM; import landptf.tools.ViewHolderM; /** * @author landptf * ListAdapter List适配器 */ public class ListAdapter extends AdapterM<MessageBean>{ public ListAdapter(Context context, int layoutId, MessageBean[] dataArray) { super(context, layoutId, dataArray); } @Override public void convert(ViewHolderM holder, MessageBean model) { // 为个控件绑定内容 holder.setText(R.id.tv_title, model.getTitle()); holder.setText(R.id.tv_content, model.getContent()); holder.setText(R.id.tv_comment, model.getComment() + "条评论"); holder.setText(R.id.tv_read, model.getRead() + "阅读"); } }
最后是Activity类,ListActivity.java
package landptf.test; import landptf.control.R; import landptf.control.TitleBarM; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; /** * @author landptf * List适配器测试类 */ public class ListActivity extends Activity{ //这里用到了之前的自定义标题栏 //如果感兴趣可以看一下我的上一篇博客,否则忽略即可 private TitleBarM tbTitle; //ListView对象 private ListView lvList; //自定义Adapter private ListAdapter listAdapter; //数据源实体,这里用数组作为示例,大家也可以选择使用List作为数据源 private MessageBean[] msgArray; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list); initView(); } private void initView() { tbTitle = (TitleBarM) findViewById(R.id.tbm_title); tbTitle.setTitleText("打造万能的适配器"); initData(); lvList = (ListView) findViewById(R.id.lv_list); listAdapter = new ListAdapter(this, R.layout.item_message, msgArray); lvList.setAdapter(listAdapter); } //装载数据 private void initData() { msgArray = new MessageBean[10]; msgArray[0] = new MessageBean("Android 自定义标题栏", "今天来看一下如何通过组合多个控件实现自定义标题栏众所周知,标题栏是应用中必不可少的控件,为了避免多次重写,将其封装起来,供每个布局调用即可。这里我们采用经典的左中右布局,也可以根据项目需要自行调整,比如在右侧再加一个控件,或者将标题偏左都可以注:其中应用到了上一篇文章中的ButtonM控件,大家可以", 0, 273); msgArray[1] = new MessageBean("android自定义控件,动态设置Button样式", "今天来看一个通过重写Button来动态实现一些效果,如圆角矩形、圆形、按下改变字体,改变背景色,改变背景图等在此说明一下,这种实现方式绝对不是唯一的,而且通过xml文件即可简单实现,这样做只是为了将控件的样式完全由代码实现,更方便打包应用于其他项目下面来看几张效果图: 图1 初始状态 图2 按下第一", 0, 400); msgArray[2] = new MessageBean("Android 自定义控件实现TextView按下后字体颜色改变", "今天跟大家分享一下Android自定义控件入门,先介绍一个简单的效果TextView,按下改变字体颜色,后期慢慢扩展更强大的功能直接看图片 第一张是按下后截的图,功能很简单,也很容易实现,下面来看一下如何通过重写TextView来实现一共三个文件 TextViewM.java,MainActivit", 0, 202); msgArray[3] = new MessageBean("Android 自定义标题栏", "今天来看一下如何通过组合多个控件实现自定义标题栏众所周知,标题栏是应用中必不可少的控件,为了避免多次重写,将其封装起来,供每个布局调用即可。这里我们采用经典的左中右布局,也可以根据项目需要自行调整,比如在右侧再加一个控件,或者将标题偏左都可以注:其中应用到了上一篇文章中的ButtonM控件,大家可以", 0, 273); msgArray[4] = new MessageBean("android自定义控件,动态设置Button样式", "今天来看一个通过重写Button来动态实现一些效果,如圆角矩形、圆形、按下改变字体,改变背景色,改变背景图等在此说明一下,这种实现方式绝对不是唯一的,而且通过xml文件即可简单实现,这样做只是为了将控件的样式完全由代码实现,更方便打包应用于其他项目下面来看几张效果图: 图1 初始状态 图2 按下第一", 0, 400); msgArray[5] = new MessageBean("Android 自定义控件实现TextView按下后字体颜色改变", "今天跟大家分享一下Android自定义控件入门,先介绍一个简单的效果TextView,按下改变字体颜色,后期慢慢扩展更强大的功能直接看图片 第一张是按下后截的图,功能很简单,也很容易实现,下面来看一下如何通过重写TextView来实现一共三个文件 TextViewM.java,MainActivit", 0, 202); msgArray[6] = new MessageBean("Android 自定义标题栏", "今天来看一下如何通过组合多个控件实现自定义标题栏众所周知,标题栏是应用中必不可少的控件,为了避免多次重写,将其封装起来,供每个布局调用即可。这里我们采用经典的左中右布局,也可以根据项目需要自行调整,比如在右侧再加一个控件,或者将标题偏左都可以注:其中应用到了上一篇文章中的ButtonM控件,大家可以", 0, 273); msgArray[7] = new MessageBean("android自定义控件,动态设置Button样式", "今天来看一个通过重写Button来动态实现一些效果,如圆角矩形、圆形、按下改变字体,改变背景色,改变背景图等在此说明一下,这种实现方式绝对不是唯一的,而且通过xml文件即可简单实现,这样做只是为了将控件的样式完全由代码实现,更方便打包应用于其他项目下面来看几张效果图: 图1 初始状态 图2 按下第一", 0, 400); msgArray[8] = new MessageBean("Android 自定义控件实现TextView按下后字体颜色改变", "今天跟大家分享一下Android自定义控件入门,先介绍一个简单的效果TextView,按下改变字体颜色,后期慢慢扩展更强大的功能直接看图片 第一张是按下后截的图,功能很简单,也很容易实现,下面来看一下如何通过重写TextView来实现一共三个文件 TextViewM.java,MainActivit", 0, 202); msgArray[9] = new MessageBean("Android 自定义标题栏", "今天来看一下如何通过组合多个控件实现自定义标题栏众所周知,标题栏是应用中必不可少的控件,为了避免多次重写,将其封装起来,供每个布局调用即可。这里我们采用经典的左中右布局,也可以根据项目需要自行调整,比如在右侧再加一个控件,或者将标题偏左都可以注:其中应用到了上一篇文章中的ButtonM控件,大家可以", 0, 273); } }
以上便是全部代码,这样以后再新增其他ListView都不需要再定义一个Adapter,一个ViewHolder,上面的ListAdapter也可以不需要,直接在Activity里实现定义AdapterM即可,但是一些复杂的列表项还是建议自定义一个Adapter去继承AdapterM.
最后本着互联网开放、分享的精神,将原视频地址附上http://www.imooc.com/learn/372,个人比较喜欢慕课网。
https://github.com/zuolg