ListView,GridView万能适配器 - 上
(相同行布局)
博主做了好多项目,没有一个项目敢说用不到ListView(下拉刷新ListView也算) ListView是安卓初级到安卓中级的纽带,学好ListView控件是很有必要。
注:刚接触不同item(行布局)的可参考:
http://blog.csdn.net/gjy_it/article/details/52014075 (下一章,不同行布局的万能适配器)
*以下几点是掌握ListView的关键:
1.了解ListView的属性布局 常用的比如数点击改变item颜色,diliver颜色 长度等
(具体还是百度把,毕竟互联网那么强大)
2.ListView可以看作的MVC模型。 那么适配器就比较重要,大多数是通过适配器改 变 View的数据显示。一般很多复杂的逻辑也是在适配器里实现,因为要掌握适 配器的各种方法以及用法甚至是优化。
3.前期可以大量练习ListView适配器的使用 ,要实践 , 实践多了,写个适配器都不 用动个脑子。
以上都是前期掌握ListView的基本要求,那么再高一点需要:
4.掌握ListView的适配器的优化。
5.多种行布局的使用
6.多种行布局 并优化
7.解决在ListView中行布局复用导致重新显示
(典型的例子就是 用listView 每个item进行下载
可参考 http://blog.csdn.net/gjy_it/article/details/52262928
)
8。就是越来越多的item。。。。。
-----------------以上都是废话,不用在意那么多细节-------------
万能适配器:说万能是骗人的,但是可以优化代码以及减少很多不必要的代码。
确实比普通手写的适配器要节省很多时间,因此推荐使用。
万能适配器的原理:
在普通的适配器中,适配器优化都通过ViewHolder来进行复用行布局。
控件也是申明在ViewHolder中,那么万能适配器会独立出一个类来专门 初始化View并存储View, 最后我们还会有一个自己定义的抽象类继承于
BaseAdapter ,因为大多数结构需要在getView中完成 ,那么, 在 getView中常用到的逻辑写在自定义的抽象类的getView里, 不确定的逻 辑通过抽象方法抽象给子类。这样就可以减少很多的代码量。
为什么要用万能适配器?
(在安卓开发中,用到ListView和GridView的地方实在是太多了,系统默认给我们提供的适配器(ArrayAdapter,SimpleAdapter)经常不能满足我们的需要,因此我们时常要去继承BaseAdapter类去实现一个自定义的适配器来满足我们的场景需要。
如果你是开发一个简单点的APP还好,可能ListView和GridView的数量不会太多,我们只要去写几个BaseAdapter实现类就可以了。
但如果有一天,你需要开发一个APP里面具有几十个ListView或者GridView的子页面,此时的你该怎么办?每个ListView或者GridView都去写一个适配的Adatper类吗?
当然你如果想做蛮牛不嫌累的话也不是不可以,但如果有办法可以让自己减少很多工作量,避免做重复无意义劳动,何乐而不为呢?)
本篇先讲 相同行布局 的用法
(这个万能适配器比较旧版本,关注下一章会介绍功能更多的万能适配器)
看下demo结构:
CommonAdapter.java就是自定义抽象的适配器
ViewHolder.java
MyModel,java 测试需要 模拟数据
那么先来看下ViewHolder是何方神圣?
package com.example.ex0_listviewadapter;
import android.content.Context;
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 gjy
*
* 通用的ViewHolder
*
* **/
public class ViewHolder {
//存放绑定的控件的容器
private final SparseArray<View> mViews;
//item视图
private View mConvertView;
private ViewHolder(Context context,ViewGroup parent,int layoutId,int position)
{
this.mViews=new SparseArray<View>();
//初始化视图
mConvertView=LayoutInflater.from(context).inflate(layoutId, parent,false);
//绑定Tag
mConvertView.setTag(this);
}
/**
* 获取Viewholder的对象 为类的入口
* @param Context 上下文
* @param convertview item视图
* @param layoutId item布局的id
* @param position 当前item的position
*
* */
public static ViewHolder get(Context context,View convertview,ViewGroup parent,int layoutId,int position)
{
if (convertview==null) {
return new ViewHolder(context, parent, layoutId, position);
}
return (ViewHolder) convertview.getTag();
}
/**
* 通过控件的id获取对于控件,如果没有加入view
* */
public <T extends View>T getView(int viewId)
{
View view=mViews.get(viewId);
if (view == null) {
view=mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T)view;
}
/***
* 为TextView 设置字符串
* **/
public ViewHolder setText(int viewId,String text)
{
TextView view=getView(viewId);
view.setText(text);
return this;
}
/***
* 为ImageView 设置图片资源
* **/
public ViewHolder setImageResource(int viewId,int drawableId)
{
ImageView img=getView(viewId);
img.setImageResource(drawableId);
return this;
}
/***
* 为ImageView 通过URL访问图片
* **/
// public ViewHolder setImageResource(int viewId,String url)
// {
// ImageView img=getView(viewId);
// UILUtils.displayImageNoAnim(url, img);
// return this;
// }
public View getConvertview()
{
return mConvertView;
}
}
解析:1.SparseArray就是稀疏数组,可以理解为HashMap,SparseArray的性能比HashMap高。
(用View对应的ID来保存View)
2.public <T extends View>T getView(int viewId) 就是通过刚刚那个SparseArray 键值 用 ID 对来 获取View
可以理解为 View v=findViewById(ID) 通过ID获的一个View
3..mConvertView.setTag(this); 以及getConvertview() get() 【获取ViewHolder对象】 都封装在这个类中
4.setXXXX 就是通过对应的ID 来获取viewHolder 中绑定的控件 并为他绑定数据
自定义抽象类:
package com.example.ex0_listviewadapter;
import java.util.List;
import android.R.integer;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public abstract class CommonAdapter<T> extends BaseAdapter {
protected LayoutInflater mInflater;
protected Context context;
protected List<T> mDatas;
protected final int mLayoutId;
/**
* @param
* **/
public CommonAdapter(Context context,List<T> mdaList,int mLayoutId) {
this.context=context;
this.mDatas=mdaList;
this.mInflater = LayoutInflater.from(context);
this.mLayoutId=mLayoutId;
}
@Override
public int getItemViewType(int position) {
// TODO Auto-generated method stub
return super.getItemViewType(position);
}
@Override
public int getViewTypeCount() {
// TODO Auto-generated method stub
return super.getViewTypeCount();
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mDatas.size();
}
@Override
public T getItem(int position) {
// TODO Auto-generated method stub
return mDatas.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
final ViewHolder viewHolder=getViewHolder(position, convertView, parent);
//抽象一个方法出去 方便进行实现
convert(viewHolder, getItem(position));
return viewHolder.getConvertview();
}
public abstract void convert(ViewHolder helper,T item);
private ViewHolder getViewHolder(int position,View converView,ViewGroup parent)
{
return ViewHolder.get(context, converView, parent, mLayoutId, position);
}
}
解析 :
来看下构造函数 public CommonAdapter(Context context,List<T> mdaList,int mLayoutId)
来再来看下ViewHolder的构造函数ViewHolder(Context context,ViewGroup parent,int layoutId,int position)
---List<T> mdaList 这个数据类 是在抽象类里面的getcount 要用到 获取总数个。 那么int mLayoutId,为布局的ID
这个是要在ViewHolder中转为View的。实现BaseAdapter的方法跟普通适配器一样。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
final ViewHolder viewHolder=getViewHolder(position, convertView, parent);
//抽象一个方法出去 方便进行实现
convert(viewHolder, getItem(position));
return viewHolder.getConvertview();
}
public abstract void convert(ViewHolder helper,T item);
private ViewHolder getViewHolder(int position,View converView,ViewGroup parent)
{
return ViewHolder.get(context, converView, parent, mLayoutId, position);
}
重点来了:
getViewHolder 方法里 通过调用ViewHolder的静态方法get获取到ViewHolder的对象
最后对数据进行绑定的时候是需要用到Viewholder(因为View都是保存在ViewHolder里)
最后:
//抽象一个方法出去 方便进行实现
convert(viewHolder, getItem(position));
ViewHolder 的对象以及数据 最后在抽象接口中只管对数据进行绑定就可以了。
多琢磨几次就懂了。来看下Demo:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<MyModel> lists=new ArrayList<MyModel>();
for (int i = 0; i < 20; i++) {
lists.add(new MyModel("A"+i, "B"+i,"C"+i));
}
ListView mListView=(ListView) findViewById(R.id.listView1);
mListView.setAdapter(new CommonAdapter<MyModel>(MainActivity.this,lists,R.layout.item_1) {
@Override
public void convert(ViewHolder helper, MyModel item) {
helper.setText(R.id.textView1, item.getTxt1());
helper.setText(R.id.textView2, item.getTxt2());
helper.setText(R.id.textView3, item.getTxt3());
}
});
}
只管在convert 里写了这么一点东西。 是不是简便了很多。
Demo下载地址(ViewHolder中有错 删除即可)
http://download.csdn.net/detail/gjy_it/9666243