老规矩,先上效果图(以每行三列为例)
下面就是放出源码,最后再给出应用的实例:
为了更好的实现view的复用,我们将ViewHolder 进行了封装。MtjBaseViewHolder,包括了ImageView、Button、TextView等常用的控件都封装在内。自己可以根据需求,进行拓展。例如源码末尾,拓展出的“使用Glide为ImageView设置网络图片”。拓展的方法,相信一看就知道,无非就是通过传入的viewid去get这个控件——getTextView(viewid),然后set这个控件想展示的数据。OK,源码:
/**
* Created by Administrator on 2017/1/2.
*/
public class MtjBaseViewHolder {
/**
* layout文件中的控件集合 SparseArray用法与HashMap类似,性能比HashMap更优
*/
private SparseArray mViews;
/**
* BaseAdapter中的getView方法中对应的参数
*/
private View mConvertView;
private Context context;
/**
* 私有,禁止外部实例化
*
* @param context
* @param parent
* BaseAdapter中的getView方法中对应的参数
* @param layoutId
* layout资源文件ID
*/
private MtjBaseViewHolder(Context context, ViewGroup parent, int layoutId) {
this.mViews = new SparseArray();
this.mConvertView = LayoutInflater.from(context).inflate(layoutId,
parent, false);
this.mConvertView.setTag(this);
this.context = context;
}
/**
*
* @param context
* @param convertView
* BaseAdapter中的getView方法中对应的参数
* @param parent
* BaseAdapter中的getView方法中对应的参数
* @param layoutId
* layout资源文件ID
* @return
*/
public static MtjBaseViewHolder get(Context context, View convertView,
ViewGroup parent, int layoutId) {
if (convertView == null) {
return new MtjBaseViewHolder(context, parent, layoutId);
}
return (MtjBaseViewHolder) convertView.getTag();
}
/**
* 根据ViewID获取控件对象,先从mViews集合中查找, 如果存在则直接返回该对象;
* 不存在则从布局文件中获取该对象,然后添加到mViews集合中,然后再返回该对象;
*
* @param
* @param viewid
* 控件ID
* @param
* @return
*/
@SuppressWarnings("unchecked")
public T getView(int viewid) {
View view = mViews.get(viewid);
if (view == null) {
view = mConvertView.findViewById(viewid);
mViews.put(viewid, view);
}
return (T) view;
}
/**
* 返回BaseAdapter中的getView方法中对应的参数(convertView)
*
* @return
*/
public View getConvertView() {
return mConvertView;
}
/**
* 获取TextView控件
*
* @param viewid
* 控件ID
* @return
*/
public TextView getTextView(int viewid) {
return (TextView) getView(viewid);
}
/**
* 获取Button控件
*
* @param viewid
* 控件ID
* @return
*/
public Button getButton(int viewid) {
return (Button) getView(viewid);
}
/**
* 获取ImageView控件
*
* @param viewid
* 控件ID
* @return
*/
public ImageView getImageView(int viewid) {
return (ImageView) getView(viewid);
}
/**
* 获取ImageButton控件
*
* @param viewid
* 控件ID
* @return
*/
public ImageButton getImageButton(int viewid) {
return (ImageButton) getView(viewid);
}
/**
* 获取LinearLayout控件
*
* @param viewid
* 控件ID
* @return
*/
public LinearLayout getLinearLayout(int viewid) {
return (LinearLayout) getView(viewid);
}
/**
* 设置TextView内容
*
* @param viewid
* TextView控件ID
* @param content
* 要设置的内容
* @return
*/
public MtjBaseViewHolder setText(int viewid, String content) {
getTextView(viewid).setText(content);
return this;
}
/**
* 为ImageView设置图片
*
* @param viewid
* ImageView控件ID
* @param resid
* 要设置的图片资源ID
* @return
*/
public MtjBaseViewHolder setImageResource(int viewid, int resid) {
getImageView(viewid).setImageResource(resid);
return this;
}
/**
* 使用Glide为ImageView设置网络图片(需要导入Glide包)
*
* @param viewid
* ImageView控件ID
* @param img_path
* 要设置的图片资源ID
* @param default_img
* 默认图片
* @param load_type
* 加载类型 【 0:正常 1:圆角(默认5dp圆角)2:圆形图片】
* @param db
* load_type = 1 时 ,设置的图片圆角大小,使用默认大小时 传 0
*
* @return
*/
public MtjBaseViewHolder setImageGlide(int viewid, int img_path,
int default_img, int load_type, int dp) {
switch (load_type) {
case 0:
Glide.with(context).load(img_path).placeholder(default_img)
.error(default_img).crossFade().into(getImageView(viewid));
break;
case 1:
if (dp <= 0) {
Glide.with(context).load(img_path).placeholder(default_img)
.transform(new GlideRoundTransform(context))
.error(default_img).crossFade()
.into(getImageView(viewid));
} else {
Glide.with(context).load(img_path).placeholder(default_img)
.transform(new GlideRoundTransform(context, dp))
.error(default_img).crossFade()
.into(getImageView(viewid));
}
break;
case 2:
Glide.with(context).load(img_path).placeholder(default_img)
.transform(new GlideCircleTransform(context))
.error(default_img).crossFade().into(getImageView(viewid));
break;
default:
break;
}
return this;
}
}
最后那个“使用Glide为ImageView设置网络图片”是我项目中用到的,如果你们想要,需要导入相应的包。
接下来就是Adapter了,注解中写的比较清楚,就不废话了,直接代码:
public abstract class MtjBaseAdapter<T> extends BaseAdapter {
protected Context mContext;
protected List listDatas = null;
protected int mLayoutId;
protected int column = 1;// 每行要显示的列数[默认是1]
protected int line_int;// 计算得到的行数
protected int column_yu;// 一行多列,不能整除时,最后一行的列数
/**
* 适配器
*
* @param context
* 上下文
* @param data
* 数据源
* @param layoutId
* layout资源文件ID
* @param setcolumn
* 设置每行要显示的列数[默认是1]
*/
public MtjBaseAdapter(Context context, List data, int layoutId,
int setcolumn) {
this.mContext = context;
this.listDatas = data;
this.mLayoutId = layoutId;
if (setcolumn >= 1) {
column = setcolumn;
}
}
@Override
public int getCount() {
column_yu = listDatas.size() % column;
if (column_yu > 0) {
line_int = listDatas.size() / column + 1;
} else {
line_int = listDatas.size() / column;
}
return line_int;
}
@Override
public T getItem(int position) {
return listDatas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
/**
* 添加单条数据项
*
* @param item
*/
public void addItem(T item) {
this.listDatas.add(item);
}
/**
* 设置数据源
*
* @param data
*/
public void setListDatas(List data) {
this.listDatas = data;
}
/**
* 清除数据源
*/
public void clear() {
this.listDatas.clear();
}
/**
* 刷新数据源
*/
public void refresh() {
this.notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
MtjBaseViewHolder holder = MtjBaseViewHolder.get(mContext, convertView,
parent, mLayoutId);
List models = new ArrayList();
int[] positions = null;
//可以被整除,正常返回每行的数据
if (column_yu == 0) {
positions = new int[column];
for (int i = 0; i < column; i++) {
int posi = position * column + i;
T model = listDatas.get(posi);
models.add(model);
positions[i] = posi;
}
} else {
//不能整除时,判断
// 是否是最后一行,是,返回剩余的列的数据
if (position == listDatas.size() / column) {
positions = new int[column_yu];
for (int i = 0; i < column_yu; i++) {
int posi = position * column + i;
T model = listDatas.get(posi);
models.add(model);
positions[i] = posi;
}
} else {
//否,正常返回每行的数据
positions = new int[column];
for (int i = 0; i < column; i++) {
int posi = position * column + i;
T model = listDatas.get(posi);
models.add(model);
positions[i] = posi;
}
}
}
convert(holder, positions, models);
return holder.getConvertView();
}
/**
* 在子类中实现该方法
*
* @param holder
* 列表项
* @param positions
* @param models
* 每行的数据集,每行有几列就返回几个model。第一列对应数据下标0,一一对应,以此类推。
* 不满列数的设置setVisibility(View.INVISIBLE);
*/
public abstract void convert(MtjBaseViewHolder holder, int[] positions,
List models);
}
因为一行可能有多列,所以在子类中实现的convert()方法返回的每行的数据集,在设置数据的时候,根据下标去遍历设置1、2、3。。。列的数据。
好了,很罗嗦的把源码给整完了,下面是实例的应用了:
1、首先是item.xml,例如每行三列,结构是这样的,代码就不贴了。。。:
我们在布局里先将每一个 ll_layout_1 设置为 android:visibility=”invisible”。是因为最后一行不是满列时,也要占位啊。。。
2、继承MtjBaseAdapter,在convert()方法里,实现自己的数据设置。
public class twoitemAdapter extends MtjBaseAdapter<SchoolModel> {
public twoitemAdapter(Context context, List data,
int layoutId, int setcolumn) {
super(context, data, layoutId, setcolumn);
// TODO Auto-generated constructor stub
}
@Override
public void convert(MtjBaseViewHolder holder, int[] positions,
List models) {
// TODO Auto-generated method stub
for (int i = 0; i < positions.length; i++) {
switch (i) {
case 0:
holder.getLinearLayout(R.id.ll_layout_1).setVisibility(
View.VISIBLE);
holder.setText(R.id.tv_zuo, models.get(i).getSchool_id());
break;
case 1:
holder.getLinearLayout(R.id.ll_layout_2).setVisibility(
View.VISIBLE);
holder.setText(R.id.tv_you, models.get(i).getSchool_id());
break;
case 2:
holder.getLinearLayout(R.id.ll_layout_3).setVisibility(
View.VISIBLE);
holder.setText(R.id.tv_san, models.get(i).getSchool_id());
break;
default:
break;
}
}
}
}
这里就体现了我们封装的MtjBaseViewHolder的优势了,例如: holder.setText(R.id.tv_zuo, models.get(i).getSchool_id());。我们只需要知道控件的id,和要设置数据就行了,什么view的复用都不要我们去想。
3、 最后就是为listview设置适配器了:
/**
* 参数说明
* @param context 上下文
* @param data 数据源
* @param layoutId layout的资源id
* @param setcolumn 设置一行要显示几列【默认是1】
*/
twoitemAdapter adapter = new twoitemAdapter(getPageContext(), list,R.layout.item_two_count, 3)
OK!从实现的多列实例来看,简直就是分分钟啊,50行代码有没有??关键是万能啊!能满足大多数的需求,有没有???
遵循记录与分享的原则,欢迎留言批评。
关注公众号,长期分享技术干货: