本文为菜鸟窝作者蒋志碧的连载。“从 0 开始开发一款直播 APP ”系列来聊聊时下最火的直播 APP,如何完整的实现一个类"腾讯直播"的商业化项目
项目地址:http://www.cniao5.com/course/10121
【从 0 开始开发一款直播 APP】3.1 高层封装之 Adapter — ListView & GridView
【从 0 开始开发一款直播 APP】3.2 高层封装之 Adapter — RecyclerView 实现单布局展示
【从 0 开始开发一款直播 APP】3.3 高层封装之 Adapter -- RecyclerView 实现多条目展示
【从 0 开始开发一款直播 APP】3.4 高层封装之 Adapter -- RecyclerView 优雅的添加 Header、Footer
一、前言
之前已经讲过 ListView、GridView 的 Adapter 封装,这次将带来 RecyclerView 的封装。
RecyclerView 是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式。该控件用于在有限的窗中展示大量数据集,它被作为 ListView 和 GridView 控件的继承者。
主要有以下功能:
1、简单数据绑定(单种 item)
2、多布局绑定 (多种 item)
**3、设置监听 **
4、优雅的添加 header、footer
老规矩,先封装 ViewHolder,再封装 Adapter。
二、ViewHolder 的封装
2.1、RecyclerView 在使用之前需要添加依赖
dependencies {
compile 'com.android.support:recyclerview-v7:25.2.0'
}
2.2、创建一个类继承 RecyclerView.ViewHolder,实现其构造函数
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
public RecyclerViewHolder(View itemView) {
super(itemView);
}
}
2.3、其它的封装和之前写过对 Adapter 封装类似,讲了封装的大致步骤,这里不细讲了,直接看 从 0 开始开发一款直播 APP | 3.1 高层封装之 Adapter — ListView & GridView,一个 getView() 获取控件,通过 SparseArray 存储控件。
private SparseArray<View> mViews;
public RecyclerViewHolder(View itemView) {
super(itemView);
this.mViews = new SparseArray<>();
}
/**
* 从ItemView获取View
* @param id ItemView里包含的ViewId
* @param <V> 返回View
* @return
*/
public <V extends View> V getView(int id) {
View view = mViews.get(id);
if (view == null) {
view = itemView.findViewById(id);
mViews.put(id, view);
}
return (V) view;
}
2.4、设置控件以及监听(采用链式编程方法)
/**
* 设置TextView的值
* @param viewId
* @param text
* @return
*/
public RecyclerViewHolder setText(int viewId, String text) {
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
/**
* 设置ImageView的值
* @param viewId
* @param resId
* @return
*/
public RecyclerViewHolder setImageResource(int viewId, int resId) {
ImageView view = getView(viewId);
view.setImageResource(resId);
return this;
}
/**
* 设置ImageView的值
* 第三方 ImageLoder Glide Picasso
* 不能直接写死第三方图片加载
* 使用自己的一套规范 ImageLoder
* @param viewId
* @return
*/
public RecyclerViewHolder setImagePath(int viewId,ImageLoder imageLoder) {
ImageView view = getView(viewId);
imageLoder.loadImage(view,imageLoder.getPath());
return this;
}
//图片加载 (对第三方库加载图片等封装)
public abstract static class ImageLoder{
private String path;
public ImageLoder(String path){
this.path = path;
}
//需要复写该方法加载图片
public abstract void loadImage(ImageView imageView,String path);
public String getPath() {
return path;
}
}
/**
* 设置是否可见
* @param viewId
* @param visible
* @return
*/
public RecyclerViewHolder setVisible(int viewId, boolean visible) {
View view = getView(viewId);
view.setVisibility(visible ? View.VISIBLE : View.GONE);
return this;
}
/**
* 设置tag
* @param viewId
* @param tag
* @return
*/
public RecyclerViewHolder setTag(int viewId, Object tag) {
View view = getView(viewId);
view.setTag(tag);
return this;
}
public RecyclerViewHolder setTag(int viewId, int key, Object tag) {
View view = getView(viewId);
view.setTag(key, tag);
return this;
}
/**
* 设置Checkable
* @param viewId
* @param checked
* @return
*/
public RecyclerViewHolder setChecked(int viewId, boolean checked) {
Checkable view = (Checkable) getView(viewId);
view.setChecked(checked);
return this;
}
//点击事件
public RecyclerViewHolder setOnClickListener(int viewId,View.OnClickListener listener) {
View view = getView(viewId);
view.setOnClickListener(listener);
return this;
}
//触摸事件
public RecyclerViewHolder setOnTouchListener(int viewId,View.OnTouchListener listener) {
View view = getView(viewId);
view.setOnTouchListener(listener);
return this;
}
//长按事件
public RecyclerViewHolder setOnLongClickListener(int viewId,View.OnLongClickListener listener) {
View view = getView(viewId);
view.setOnLongClickListener(listener);
return this;
}
三、Adapter 的封装
首先创建 Adapter 并继承 RecyclerView.Adapter
,将 ViewHolder 作为范型传入,将数据作为范型传入,并实现其方法。方法和 ListView 封装类似,传入布局,数据,上下文,通过 onCreateViewHolder()
实例化 ViewHolder,onBindViewHolder()
绑定 ViewHolder,用于数据,事件绑定,将该方法抽象出去,让用户实现,用户通过该方法拿到 item 对象。
public abstract class RecyclerViewAdapter<T> extends RecyclerView.Adapter<RecyclerViewHolder> {
protected int mLayoutId;//布局id
protected List<T> mDatas;//数据源
protected Context mContext;//上下文
private LayoutInflater mInflater;
public RecyclerViewAdapter(Context context, int layoutId, List<T> datas) {
this.mContext = context;
this.mLayoutId = layoutId;
this.mDatas = datas;
this.mInflater = LayoutInflater.from(mContext);
}
@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(mLayoutId,parent,false);
return new RecyclerViewHolder(itemView);
}
@Override
public void onBindViewHolder(RecyclerViewHolder holder, final int position) {
bindData(holder,mDatas.get(position),position);
}
/**
* 把必要参数传进去,让每个 Adapter 去设置具体值
* @param holder RecyclerViewHolder
* @param t 数据
* @param position 当前位置
*/
protected abstract void bindData(RecyclerViewHolder holder, T t,int position);
@Override
public int getItemCount() {
return mDatas.size();
}
}
四、Demo 演示单布局显示
4.1、由于用到网络图片,我使用的Glide加载,先添加依赖
dependencies {
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.android.support:recyclerview-v7:25.2.0'
}
4.2、在 AndroidManifest.xml 中添加网络访问权限
<uses-permission android:name="android.permission.INTERNET"/>
4.3、创建一个类继承 RecyclerView.ViewHolder,实现其构造函数
RecyclerAdapterDemo.java
public class RecyclerAdapterDemo extends RecyclerViewAdapter<Item> {
public RecyclerAdapterDemo(Context context, List<Item> datas) {
super(context, R.layout.list_item, datas);
}
@Override
protected void bindData(RecyclerViewHolder holder, final Item item, int position) {
holder.setText(R.id.tv1,item.getTv1())
// .setImageResource(R.id.img,item.getRes())
.setOnClickListener(R.id.tv1, new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,item.getTv1(),Toast.LENGTH_SHORT).show();
}
}).setOnLongClickListener(R.id.tv1, new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Toast.makeText(mContext,"长按:"+item.getTv1(),Toast.LENGTH_SHORT).show();
return true;//true 表示不响应点击事件 false 长按事件结束还会响应点击事件
}
});
//加载网络图片
holder.setImagePath(R.id.img, new RecyclerViewHolder.ImageLoder("http://tomcat.apache.org/images/tomcat.png") {
@Override
public void loadImage(ImageView imageView, String path) {
Glide.with(mContext).load(path).into(imageView);
}
});
}
}
4.5、单布局 Adapter 的使用
public class AdapterActivity extends BaseActivity {
private RecyclerAdapterDemo mAdapterDemo;
private ArrayList<Item> Datas;
private RecyclerView mRecyclerView;
@Override
protected void setToolbar() {
}
@Override
protected void setListener() {
}
//填充数据
@Override
protected void initData() {
Datas = new ArrayList<>();
for (int i = 1; i <= 30; i++) {
Datas.add(new Item(R.drawable.tab_publish_normal,"我 get 新技能 " + i));
}
mAdapterDemo = new RecyclerAdapterDemo(this, Datas);
mRecyclerView.setAdapter(mAdapterDemo);
}
@Override
protected void initView() {
mRecyclerView = obtainView(R.id.recyclerView);
//LinearLayoutManager
//添加分割线
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
//添加布局管理器
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
//分割线网上有很多示例,这里不贴代码
//GridLayoutManager
// mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));
// mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
}
@Override
protected int getLayoutId() {
return R.layout.activity_adapter;
}
}
4.6、activity_adapter.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.dali.admin.fragment.AdapterActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
五、运行效果
**5.1、LinearLayoutManager **
5.2、GridLayoutManager
总结
单条目封装步骤
1、 ViewHolder 的封装,继承 RecyclerView.ViewHolder,实现其方法和构造函数
2、封装 ViewHolder 的 getView() 方法,避免 findViewById 及类型转换,提供设置控件和监听的一系列方法
3、Adapter 的封装,继承 RecyclerView.Adapter 类,将封装的 ViewHolder 作为范型传入,将数据源作为范型传入。如:BaseAdapter<T> extends RecyclerView.Adapter<BaseViewHolder>。实现其构造方法和抽象方法。
4、设置数据源,上下文对象,布局 ID,抽象绑定 ViewHolder 具体实现,将 ViewHolder 和数据源作为参数传递出去,让用户对数据进行相应处理。
单条目 Adapter 封装及其使用讲解完,下一章讲解多条目 Adapter 封装
</br>
关注菜鸟窝官网,免费领取“140套开源项目”
</br>
菜鸟窝官网公号二维码.png
</br>
扫码进菜鸟直播学习群,与大咖交流
</br>
菜鸟直播二维码.png
网友评论