本来这一个主题应该早就写了,只是项目多,属于自己的时间不多,所以现在才开动!!
前一段时间写了一篇文章,是关于ListView,GriView万能适配器,没有看过的同学,可以先看看那篇文章,然后在来学习RecyclerView的话,会容易很多。链接http://www.cnblogs.com/huangjialin/p/7661328.html
当然,如果对RecyclerView基础不是了解的朋友,建议先去熟悉一下RecyclerView的基础知识!
闲话不多说,先简单的介绍一下这个RecyclerView,它是Android5.0的时候出来的一个新控件,主要目的就是替代ListView和GridView,也就是说RecyclerView能够实现ListView和GridView的效果,甚至比原来的更好,更方便,
我们知道,在写ListView和GridView的时候,都需要写一个适配器,然后继承BaseAdapter,接着实现几个方法,套路都是一样的,但是前一段时间写了一个通用的适配器,所以在写ListView和GridView的adapter的时候,可以省了很多事,方便了许多,那么,问题来了,
RecyclerView的通用适配器怎么写呢???
我们知道,在写ListView和GridView的适配器时候,我们需要考虑view的复用机制,但是RecyclerView内部已经帮我们写好了复用机制,所以,我们不需要考虑复用的情况,先不说,从ViewHolder开始
通用ViewHoler
1 package com.xiaoma.xting.adapter;
2
3 import android.content.Context;
4 import android.support.v7.widget.RecyclerView;
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 /**
13 * Created by Administrator on 2017/11/6 0006.
14 * huangjialin
15 */
16
17 public class BaseViewHolder extends RecyclerView.ViewHolder {
18 private SparseArray<View> mViews; //用来存储控件
19 private View mConvertView;
20 private Context mContext;
21
22
23 public BaseViewHolder(Context context, View itemView) {
24 super(itemView);
25 this.mContext = context;
26 mConvertView = itemView;
27 mViews = new SparseArray<View>();
28 }
29
30
31 /**
32 * 提供一个获取ViewHolder的方法
33 */
34 public static BaseViewHolder getRecyclerHolder(Context context, ViewGroup parent, int layoutId) {
35 View itemView = LayoutInflater.from(context).inflate(layoutId, parent, false);
36 BaseViewHolder viewHolder = new BaseViewHolder(context, itemView);
37 return viewHolder;
38 }
39
40
41 /**
42 * 获取控件
43 */
44 public <T extends View> T getView(int viewId) {
45 View view = mViews.get(viewId);
46 if (view == null) {
47 view = mConvertView.findViewById(viewId);
48 mViews.put(viewId, view);
49 }
50 return (T) view;
51 }
52
53
54 /**
55 * 给TextView设置setText方法
56 */
57 public BaseViewHolder setText(int viewId, String text) {
58 TextView tv = getView(viewId);
59 tv.setText(text);
60 return this;
61 }
62
63
64 /**
65 * 给ImageView设置setImageResource方法
66 */
67 public BaseViewHolder setImageResource(int viewId, int resId) {
68 ImageView view = getView(viewId);
69 view.setImageResource(resId);
70 return this;
71 }
72
73 /**
74 * 添加点击事件
75 */
76 public BaseViewHolder setOnClickListener(int viewId, View.OnClickListener listener) {
77 View view = getView(viewId);
78 view.setOnClickListener(listener);
79 return this;
80 }
81 }
代码中,创建了BaseViewHolder,并且继承RecyclerView的ViewHoler,我们对外提供两个方法,一个是获取viewholder的getRecyclerHolder()方法,另一个是获取控件的getView()方法,由于RecyclerView的保存控件的方式是以变量的形式来,而这里则是通过SparseArray来通过key来进行存储的。
通用适配器
前面viewholer,现在看看adapter,先上代码
1 package com.example.administrator.recylerviewadaptertest;
2
3 import android.content.Context;
4 import android.support.v7.widget.RecyclerView;
5 import android.view.ViewGroup;
6
7 import java.util.List;
8
9 /**
10 * Created by Administrator on 2017/11/6 0006.
11 * huangjialin
12 * 普通类型的适配器
13 */
14
15 public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<BaseViewHolder> {
16 private Context mContext;
17 private int mLayoutId;
18 private List<T> mData;
19
20
21 public BaseRecyclerAdapter(Context mContext, int mLayoutId, List<T> mData) {
22 this.mContext = mContext;
23 this.mLayoutId = mLayoutId;
24 this.mData = mData;
25 }
26
27 @Override
28 public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
29 BaseViewHolder viewHolder = BaseViewHolder.getRecyclerHolder(mContext, parent, mLayoutId);
30 return viewHolder;
31 }
32
33 @Override
34 public void onBindViewHolder(BaseViewHolder holder, int position) {
35 convert(holder, mData.get(position));
36
37 }
38
39 @Override
40 public int getItemCount() {
41 return mData.size();
42 }
43
44 /**
45 * 对外提供的方法
46 */
47 public abstract void convert(BaseViewHolder holder, T t);
48
49 }
代码不多,也相对简单,在onCreateViewHolder()方法中,获取到viewholer,然后我们自己定义一个convert()方法,对外提供该方法。那么,我们怎么用呢?
1 package com.example.administrator.recylerviewadaptertest;
2
3 import android.app.Activity;
4 import android.support.v7.app.AppCompatActivity;
5 import android.os.Bundle;
6 import android.support.v7.widget.LinearLayoutManager;
7 import android.support.v7.widget.RecyclerView;
8 import android.widget.TextView;
9
10 import java.util.ArrayList;
11 import java.util.List;
12
13 public class MainActivity extends Activity {
14 private RecyclerView recycler;
15 private BaseRecyclerAdapter mAdapter;
16 private List<String> stringList = new ArrayList<String>();
17
18 @Override
19 protected void onCreate(Bundle savedInstanceState) {
20 super.onCreate(savedInstanceState);
21 setContentView(R.layout.activity_main);
22
23 recycler = findViewById(R.id.recycler);
24
25 mAdapter = new BaseRecyclerAdapter<String>(this, R.layout.rl_item_view, stringList) {
26 @Override
27 public void convert(BaseViewHolder holder, String s) {
28 holder.setText(R.id.test, s);
29 }
30 };
31
32 LinearLayoutManager manager = new LinearLayoutManager(this);
33 recycler.setLayoutManager(manager);
34 recycler.setAdapter(mAdapter);
35
36
37 for (int i = 0; i < 50; i++) {
38 stringList.add("测试-->" + i);
39 }
40 mAdapter.notifyDataSetChanged();
41
42
43 }
44 }
这些都相对来说很简单如果有朋友觉得看不懂的话,我强烈建议先去看一下前面写的ListView通用适配器,然后回来你就会发现很简单了,套路都是差不多。
ItemViewType
前面写的相对来说是针对与一些常见的列表布局,如果说复杂一些的布局,可能就行不通了,比如说我一个列表第一个item垂直显示若干个控件,第二个item我水平显示若干个控件,按照以往的经验,我们通常会
在adapter中实现getItemViewType()方法,然后进行一些判断,但是通用适配器中改怎么实现呢??
从前面获取viewholder的时候,我们知道viewholder是通过布局来id来进行获取的,那么,我们能不能这样写呢,我们通过不同的布局,来获取不同的viewholder呢
我们在BaseRecyclerAdapter中加上这个接口
1 /**
2 * 针对多种类型的itemView
3 * @param <T>
4 */
5 public interface ConmonItemType<T> {
6 int getLayoutId(int itemType); //不同的Item的布局
7
8 int getItemViewType(int position, T t); //type
9 }
然后我们新创建一个adapter并且继承BaseRecyclerAdapter,代码:
1 package com.example.administrator.recylerviewadaptertest;
2
3 import android.content.Context;
4 import android.view.ViewGroup;
5
6 import java.util.List;
7
8 /**
9 * Created by Administrator on 2017/11/6 0006.
10 * huangjialin
11 * 如果列表的布局item有多种类型,则需要继承该适配器
12 */
13
14 public abstract class MultiItemCommonAdapter<T> extends BaseRecyclerAdapter<T> {
15 private ConmonItemType<T> mConmonItemType;
16 private List<T> mDatas;
17 private Context mContext;
18
19
20 public MultiItemCommonAdapter(Context mContext, List<T> mData, ConmonItemType<T> conmonItemType) {
21 super(mContext, -1, mData);
22 this.mConmonItemType = conmonItemType;
23 mDatas = mData;
24 this.mContext = mContext;
25 }
26
27 @Override
28 public int getItemViewType(int position) {
29 return mConmonItemType.getItemViewType(position, mDatas.get(position));
30 }
31
32
33 @Override
34 public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
35 int layoutId = mConmonItemType.getLayoutId(viewType);
36 BaseViewHolder holder = BaseViewHolder.getRecyclerHolder(mContext, parent, layoutId);
37 return holder;
38 }
39 }
从代码可以看出,我们通过构造方法从外面传进来的ConmonItemType<T> conmonItemType,通过这个来获取不同的布局,从而获取到不同的viewholer,看看怎么使用:
1 package com.example.administrator.recylerviewadaptertest;
2
3 import android.app.Activity;
4 import android.support.v7.app.AppCompatActivity;
5 import android.os.Bundle;
6 import android.support.v7.widget.LinearLayoutManager;
7 import android.support.v7.widget.RecyclerView;
8 import android.util.Log;
9 import android.widget.TextView;
10
11 import java.util.ArrayList;
12 import java.util.List;
13
14 public class MainActivity extends Activity {
15 private RecyclerView recycler;
16 private BaseRecyclerAdapter mAdapter;
17 private List<String> stringList = new ArrayList<String>();
18
19
20 private MultiItemCommonAdapter adapter;
21 private int typeOne = 1;
22 private int typeTwo = 2;
23
24 @Override
25 protected void onCreate(Bundle savedInstanceState) {
26 super.onCreate(savedInstanceState);
27 setContentView(R.layout.activity_main);
28
29 recycler = findViewById(R.id.recycler);
30
31 /**
32 * 普通的列表形式
33 */
34 // mAdapter = new BaseRecyclerAdapter<String>(this, R.layout.rl_item_view, stringList) {
35 // @Override
36 // public void convert(BaseViewHolder holder, String s) {
37 // holder.setText(R.id.test, s);
38 // }
39 // };
40 //
41 // LinearLayoutManager manager = new LinearLayoutManager(this);
42 // recycler.setLayoutManager(manager);
43 // recycler.setAdapter(mAdapter);
44 //
45 //
46 // for (int i = 0; i < 50; i++) {
47 // stringList.add("测试-->" + i);
48 // }
49 // mAdapter.notifyDataSetChanged();
50
51
52 /**
53 * 不同item布局的形式
54 */
55 BaseRecyclerAdapter.ConmonItemType conmonItemType = new BaseRecyclerAdapter.ConmonItemType<String>() {
56
57 @Override
58 public int getLayoutId(int itemType) {
59 if (itemType == typeOne) {
60 return R.layout.item_one;
61 } else {
62 return R.layout.item_two;
63 }
64 }
65
66 @Override
67 public int getItemViewType(int position, String s) {
68 if (position == 0) {
69 return typeOne;
70 } else {
71 return typeTwo;
72 }
73 }
74 };
75
76
77 for (int i = 0; i < 2; i++) {
78 stringList.add("测试-->" + i);
79 }
80
81
82 adapter = new MultiItemCommonAdapter<String>(this, stringList, conmonItemType) {
83 @Override
84 public void convert(BaseViewHolder holder, String s) {
85 if (holder.getItemViewType() == 0) {
86 //Todo
87
88 } else {
89 //Todo
90 }
91 }
92 };
93 LinearLayoutManager manager = new LinearLayoutManager(this);
94 recycler.setLayoutManager(manager);
95 recycler.setAdapter(adapter);
96
97 }
98 }
在这里我是自己定义的typeone,和typetwo,在项目中我们可以根据bean来进行判断,不同的类型,返回不同的值,从而获取不同的item布局,ok,这样的话,我们的多种ItemViewType的支持也就完成了
源码链接:https://github.com/343661629/RecyclerView-