RecycleView终极封装(添加头、尾)
时间:2022-06-19
本文章向大家介绍RecycleView终极封装(添加头、尾),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
今天给大家带来一个对于Recycleview的终极封装包含头、尾。
背景
Recycleview可以说是我们最常用的控件之一,只要有列表几乎就会用到。但是有没有因为每次要重写一大堆一样的相同代码而感到烦恼和厌倦,我们就想到能不能把相同内容进行封装,答案当然是可以,根据我们目前项目里的需求,又加上了头、尾布局。
效果
首先我们通过几个GIF来展示一下我们实现的效果
以上三种状态我们都会通过后面的代码来详细说明。
代码实现
头布局
头布局没什么可说的,在ListView当中可以直接通过addHeaderView()进行添加头布局,但是对于Recyclerview当中,并没有这种直接添加头布局的方法,那么我们就需要通过Adapter当中来实现。
尾布局
尾布局,我们设定有三种不同的模式,这个在我们下拉加当中可能遇到的情况 1.自动加载 AUTO_LOAD 2.加载到底 LOAD_END 3.加载失败 LOAD_ERROR 根据不同的布局我们设置了不同的提示语 <string name="list_index_auto_loading">(>﹏<) 卖力加载中~</string> <string name="list_index_loading_end">(>﹏<) 暂时就这么多了~</string> <string name="list_index_loading_error">(>﹏<) 点我加载更多~</string>
点击事件
因为Recycleview本身并没有点击事件,自然我们需要添加上点击事件,同时我们对头布局,尾布局都增加点击事件 完整的BaseRecycleViewAdapter代码如下:
public abstract class BaseRecycleViewAdapter<T> extends RecyclerView.Adapter {
public static final int TYPE_NORMAL = 0;
public static final int TYPE_HEADER = 1;
public static final int TYPE_FOOTER = 2;
public static final int TYPE_AUTO_MORE = 3;
private AutoMoreListener mMoreListener;
protected List<T> mList;
protected Context mContext;
protected OnItemClickListener<T> mOnItemClickListener;
protected OnItemLongClickListener mOnItemLongClickListener;
protected OnHeaderItemClickListener mOnHeaderItemClickListener;
private MORE_TYPE mMoreType = MORE_TYPE.AUTO_LOAD;
public enum MORE_TYPE {
AUTO_LOAD, LOAD_END, LOAD_ERROR
}
protected BaseRecycleViewAdapter(Context context, List<T> list) {
mContext = context;
mList = list;
}
protected int getRealPosition(int position) {
if (getViewHeaderResource() > 0) {
return position - 1;
} else {
return position;
}
}
@Override
public int getItemViewType(int position) {
if (getMoreLoadLayoutResId() > 0 && position == getItemCount() - 1) {
return TYPE_AUTO_MORE;
}
if (position == 0) {
if (mList == null || mList.isEmpty()) {
if (getViewHeaderResource() > 0) {
return TYPE_HEADER;
} else if (getFooterViewResource() > 0) {
return TYPE_FOOTER;
} else {
return TYPE_NORMAL;
}
} else {
if (getViewHeaderResource() > 0) {
return TYPE_HEADER;
} else {
return TYPE_NORMAL;
}
}
} else if (position == getItemCount() - 1) {
if (getFooterViewResource() > 0) {
return TYPE_FOOTER;
} else {
return TYPE_NORMAL;
}
} else {
return TYPE_NORMAL;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
return getRecycleViewHeaderHolder(LayoutInflater.from(mContext).inflate(getViewHeaderResource(), parent, false));
} else if (viewType == TYPE_FOOTER) {
return getRecycleViewFooterHolder(LayoutInflater.from(mContext).inflate(getFooterViewResource(), parent, false));
} else if (viewType == TYPE_AUTO_MORE) {
return new MoreLoadViewHolder(LayoutInflater.from(mContext).inflate(getMoreLoadLayoutResId(), parent, false));
} else {
return getRecycleViewHolder(LayoutInflater.from(mContext).inflate(getViewResource(), parent, false));
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final int viewType = getItemViewType(position);
if (viewType == TYPE_AUTO_MORE) {
bindMoreViewHolder((MoreLoadViewHolder) holder);
return;
}
if (viewType == TYPE_HEADER) {
dataReadByHeader(holder, position);
if (mOnHeaderItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnHeaderItemClickListener.onHeaderClick(holder.itemView, position, mList.get(position));
}
});
}
} else if (viewType == TYPE_FOOTER) {
dataReadByFooter(holder, position);
} else {
final int pos = getRealPosition(position);
dataRead(holder, pos);
if (mOnItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (viewType != TYPE_NORMAL) {
return;
}
mOnItemClickListener.onItemClick(holder.itemView, position, mList.get(pos));
}
});
}
if (mOnItemLongClickListener != null) {
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (viewType != TYPE_NORMAL) {
return false;
} else {
mOnItemLongClickListener.onItemLongClick(holder.itemView, position, mList.get(pos));
return true;
}
}
});
}
}
}
@Override
public int getItemCount() {
int count = mList == null ? 0 : mList.size();
if (count == 0) {
return count;
}
if (getViewHeaderResource() > 0) {
count += 1;
}
if (getFooterViewResource() > 0) {
count += 1;
}
if (getMoreLoadLayoutResId() > 0) {
count += 1;
}
return count;
}
protected static class MoreLoadViewHolder extends RecyclerView.ViewHolder {
private TextView mTvMsg;
public MoreLoadViewHolder(View itemView) {
super(itemView);
mTvMsg = (TextView) itemView.findViewById(R.id.tv_more_loading);
}
}
protected int getMoreLoadLayoutResId() {
return R.layout.item_new_more_footer_layout;
}
private void bindMoreViewHolder(MoreLoadViewHolder holder) {
if (mMoreType == MORE_TYPE.AUTO_LOAD) {
holder.mTvMsg.setText(mContext.getString(R.string.list_index_auto_loading));
} else if (mMoreType == MORE_TYPE.LOAD_END) {
holder.mTvMsg.setText(getFooterTip());
} else if (mMoreType == MORE_TYPE.LOAD_ERROR) {
holder.mTvMsg.setText(mContext.getString(R.string.list_index_loading_error));
holder.mTvMsg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mMoreListener != null) {
setMoreType(MORE_TYPE.AUTO_LOAD);
notifyDataSetChanged();
mMoreListener.load();
}
}
});
}
}
protected abstract int getViewResource();
protected int getViewHeaderResource() {
return 0;
}
protected int getFooterViewResource() {
return 0;
}
protected RecyclerView.ViewHolder getRecycleViewHeaderHolder(View view) {
throw new NullPointerException("getRecycleViewHeaderHolderv not init");
}
protected RecyclerView.ViewHolder getRecycleViewFooterHolder(View view) {
throw new NullPointerException("getRecycleViewFooterHolder not init");
}
protected abstract RecyclerView.ViewHolder getRecycleViewHolder(View view);
protected abstract void dataRead(RecyclerView.ViewHolder holder, int position);
protected void dataReadByHeader(RecyclerView.ViewHolder holder, int position) {
throw new NullPointerException("dataReadByHolder not init");
}
protected void dataReadByFooter(RecyclerView.ViewHolder holder, int position) {
throw new NullPointerException("dataReadByFooter not init");
}
/**
* 由于不同列表底部显示的东西可能不一样 所以由子类传入
*
* @return
*/
protected String getFooterTip() {
return mContext.getString(R.string.list_index_loading_end);
}
public interface OnItemClickListener<T> {
void onItemClick(View view, int position, T entity);
}
public interface OnItemLongClickListener<T> {
void onItemLongClick(View view, int position, T entity);
}
public interface OnHeaderItemClickListener<T> {
void onHeaderClick(View view, int position, T entity);
}
public void setOnItemClickListener(OnItemClickListener<T> listener) {
mOnItemClickListener = listener;
}
public void setOnHeaderItemClickListener(OnHeaderItemClickListener<T> listener) {
mOnHeaderItemClickListener = listener;
}
public void setOnItemLongClickListener(OnItemLongClickListener<T> itemLongClickListener) {
mOnItemLongClickListener = itemLongClickListener;
}
public void setMoreType(MORE_TYPE moreType) {
mMoreType = moreType;
}
public MORE_TYPE getMoreType() {
return mMoreType;
}
public void setMoreListener(AutoMoreListener listener) {
mMoreListener = listener;
}
public interface AutoMoreListener {
void load();
}
}
有了这个BaseRecycleViewAdapter那么我们再写Adapter的时候,直接继承这个BaseRecycleViewAdapter就可以了 我是用Kotlin写的,习惯用Java的小伙伴自行转成Java
package demo.rlv.cehome.com.alldemo.view
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.View
import android.widget.TextView
import demo.rlv.cehome.com.myapplication.R
import demo.rlv.view.BaseRecycleViewAdapter
/**
* @author yangzc
* @data 2019/3/14 10:56
* @desc
*/
open class RlvAdapter(context: Context, list: List<String>) : BaseRecycleViewAdapter<String>(context, list as MutableList<String>?) {
override fun getViewResource(): Int {
return R.layout.item_normal
}
override fun getViewHeaderResource(): Int {
return return R.layout.item_head
}
override fun getRecycleViewHolder(view: View): RecyclerView.ViewHolder {
return RlvViewHolder(view)
}
override fun dataRead(holder: RecyclerView.ViewHolder, position: Int) {
val h = holder as RlvViewHolder
h.tv.text = mList[position]
}
override fun getRecycleViewHeaderHolder(view: View): RecyclerView.ViewHolder {
return RlvHeadViewHolder(view)
}
override fun dataReadByHeader(holder: RecyclerView.ViewHolder?, position: Int) {
val h = holder as RlvHeadViewHolder
h.tv_head.text = "这个是头部"
}
private inner class RlvViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal val tv: TextView = itemView.findViewById(R.id.tv)
}
private inner class RlvHeadViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal val tv_head: TextView = itemView.findViewById(R.id.tv_head)
}
}
项目地址
https://github.com/yang0range/BaseRecycleView
- 《OEA - 实体扩展属性系统 - 设计方案说明书》
- webview与js的相互交互
- Java与js的交互
- Rafy 框架 - 流水号插件
- 产品前端重构(TypeScript、MVC框架设计)
- 寻找最优持仓期的开盘缺口盈利交易策略基于Matlab
- Android SlidingMenu 侧拉菜单的使用(详细配置)
- Rafy 框架 - 幽灵插件(假删除)
- 用粒子群优化算法求解旅行商问题
- 使用CNN(LSTM架构)进行序列预测基于TensorFlow
- 【独家】周志华教授gcForest(多粒度级联森林)算法预测股指期货涨跌
- 如何利用SOTER,1个版本内完成指纹支付开发?
- Rafy 框架 - 大批量导入实体
- Rafy 框架 - 执行SQL或存储过程
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java多线程编程核心技术
- oracle 常用函数
- oracle 笔记
- Jackson笔记
- 每日一题 | 两个序列归并问题
- Java基础之IO流(一)
- Java基础之IO流(二)
- 数据可视化|如何用wordcloud绘制词云图?
- Java日志记录最佳实践
- Java基础之IO流(三)
- 百万并发「零拷贝」技术系列之Linux实现
- 前缀和与差分 Krains 2020-07-28 16:05:15
- 1477. 找两个和为目标值且不重叠的子数组 Krains 2020-07-30 09:50:18 动态规划滑动窗口
- 114. 二叉树展开为链表 Krains 2020-08-02 08:59:00 树
- 1478. 安排邮筒 Krains 2020-07-30 14:51:32 动态规划DFS数学