您的位置:首页 > 移动开发 > Android开发

Android 解析RecyclerView(3)——以更简单的方法实现带顶部View和底部View的RecyclerView

2017-06-07 08:31 876 查看
在上一篇文章:解析RecyclerView(2)——带顶部View和底部View的RecyclerView ,我介绍了如何为RecyclerView 添加头部View和底部View,功能虽然实现了,不过需要用到的类也相对较多。其实可以像我在第一篇文章里介绍的使用泛型来适应不同情况那样,同样可以在 WrapRecyclerViewAdapter 中使用泛型,这样会使代码更为简洁

如果看过我前两篇文章了,以下代码应该就很容易理解了

一、通用ViewHolder

/**
* 通用ViewHolder
* Created by ZY on 2017/6/3.
*/
public class GeneralWrapRecyclerHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {

public interface onClickCommonListener {

void onClick(int position);

void onLongClick(int position);

}

private onClickCommonListener clickCommonListener;

//用来存放View以减少findViewById的次数
private SparseArray<View> viewSparseArray;

public GeneralWrapRecyclerHolder(View itemView) {
super(itemView);
viewSparseArray = new SparseArray<>();
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}

public void setClickCommonListener(onClickCommonListener clickCommonListener) {
this.clickCommonListener = clickCommonListener;
}

@Override
public void onClick(View view) {
if (clickCommonListener != null) {
clickCommonListener.onClick(getAdapterPosition());
}
}

@Override
public boolean onLongClick(View view) {
if (clickCommonListener != null) {
clickCommonListener.onLongClick(getAdapterPosition());
}
return true;
}

/**
* 根据 ID 来获取 View
*
* @param viewId viewID
* @param <T>    泛型
* @return 将结果强转为 View 或 View 的子类型
*/
private <T extends View> T getView(int viewId) {
// 先从缓存中找,找到的话则直接返回
// 如果找不到则findViewById,再把结果存入缓存中
View view = viewSparseArray.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
viewSparseArray.put(viewId, view);
}
return (T) view;
}

public GeneralWrapRecyclerHolder setText(int viewId, CharSequence text) {
TextView tv = getView(viewId);
tv.setText(text);
return this;
}

public GeneralWrapRecyclerHolder setImageResource(int viewId, int resourceId) {
ImageView imageView = getView(viewId);
imageView.setImageResource(resourceId);
return this;
}

public GeneralWrapRecyclerHolder setImageResource(int viewId, Bitmap bitmap) {
ImageView imageView = getView(viewId);
imageView.setImageBitmap(bitmap);
return this;
}

public GeneralWrapRecyclerHolder setViewVisibility(int viewId, int visibility) {
getView(viewId).setVisibility(visibility);
return this;
}

}


二、GeneralWrapRecyclerAdapter

/**
* 可以带头部View与尾部View的RecyclerView Adapter
* Created by CZY on 2017/6/4.
*/
public abstract class GeneralWrapRecyclerAdapter<T> extends RecyclerView.Adapter<GeneralWrapRecyclerHolder> {

public interface MultiTypeSupport<T> {

int getLayoutId(T item, int position);

}

private LayoutInflater layoutInflater;

private List<T> dataList;

private int layoutId;

private MultiTypeSupport<T> multiTypeSupport;

private GeneralWrapRecyclerHolder.onClickCommonListener clickCommonListener;

private SparseArray<View> headerViews;

private SparseArray<View> footerViews;

//头部类型开始位置,用于viewType
private int BASE_ITEM_TYPE_HEADER = 1000;

//底部类型开始位置,用于viewType
private int BASE_ITEM_TYPE_FOOTER = 2000;

/**
* 私有构造函数
*
* @param context  上下文
* @param dataList 数据集合
*/
private GeneralWrapRecyclerAdapter(Context context, List<T> dataList) {
this.layoutInflater = LayoutInflater.from(context);
this.dataList = dataList;
headerViews = new SparseArray<>();
footerViews = new SparseArray<>();
}

/**
* 适用于:列表所有的子项都使用相同的布局文件,且不需要监听点击事件
*
* @param context  上下文
* @param dataList 数据集合
* @param layoutId 布局文件ID
*/
protected GeneralWrapRecyclerAdapter(Context context, List<T> dataList, int layoutId) {
this(context, dataList);
this.layoutId = layoutId;
}

/**
* 适用于:列表的子项使用不同的布局文件,且不需要监听点击事件
*
* @param context          上下文
* @param dataList         数据集合
* @param multiTypeSupport 支持多个布局文件
*/
protected GeneralWrapRecyclerAdapter(Context context, List<T> dataList, MultiTypeSupport<T> multiTypeSupport) {
this(context, dataList);
this.multiTypeSupport = multiTypeSupport;
}

/**
* 适用于:列表所有的子项都使用相同的布局文件,且需要监听点击事件
*
* @param context             上下文
* @param dataList            数据集合
* @param layoutId            布局文件ID
* @param clickCommonListener 点击事件监听
*/
protected GeneralWrapRecyclerAdapter(Context context, List<T> dataList, int layoutId,
GeneralWrapRecyclerHolder.onClickCommonListener clickCommonListener) {
this(context, dataList, layoutId);
this.clickCommonListener = clickCommonListener;
}

/**
* 适用于:列表的子项使用不同的布局文件,且需要监听点击事件
*
* @param context             上下文
* @param dataList            数据集合
* @param multiTypeSupport    支持多个布局文件
* @param clickCommonListener 点击事件监听
*/
protected GeneralWrapRecyclerAdapter(Context context, List<T> dataList, MultiTypeSupport<T> multiTypeSupport,
GeneralWrapRecyclerHolder.onClickCommonListener clickCommonListener) {
this(context, dataList, multiTypeSupport);
this.clickCommonListener = clickCommonListener;
}

/**
* 根据索引判断该位置的View类型
* 如果是头部,则返回该View在headerViews中的key
* 如果是底部,则返回该View在footerViews中的key
*
* @param position 索引
* @return View类型
*/
@Override
public int getItemViewType(int position) {
if (isHeaderPosition(position)) {
return headerViews.keyAt(position);
}
if (isFooterPosition(position)) {
position = position - headerViews.size() - getDataItemCount();
return footerViews.keyAt(position);
}
position = position - headerViews.size();
if (multiTypeSupport != null) {
return multiTypeSupport.getLayoutId(dataList.get(position), position);
}
return super.getItemViewType(position);
}

@Override
public GeneralWrapRecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (isHeaderViewType(viewType)) {
return createHeaderFooterViewHolder(headerViews.get(viewType));
}
if (isFooterViewType(viewType)) {
return createHeaderFooterViewHolder(footerViews.get(viewType));
}
if (multiTypeSupport != null) {
layoutId = viewType;
}
View view = layoutInflater.inflate(layoutId, parent, false);
return new GeneralWrapRecyclerHolder(view);
}

@Override
public void onBindViewHolder(GeneralWrapRecyclerHolder holder, int position) {
holder.setClickCommonListener(clickCommonListener);
if (isHeaderPosition(position) || isFooterPosition(position)) {
return;
}
bindData(holder, dataList.get(position - getHeaderItemCount()));
}

/**
* 获取列表总的条数(头部View个数+列表条数+底部View个数)
*
* @return 总的条数
*/
@Override
public int getItemCount() {
return dataList.size() + headerViews.size() + footerViews.size();
}

/**
* 获取不包含头部和底部View之后列表的条数
*
* @return 列表条数
*/
private int getDataItemCount() {
return dataList.size();
}

protected abstract void bindData(GeneralWrapRecyclerHolder holder, T data);

/**
* 获取头部View数量
*
* @return 头部View数量
*/
private int getHeaderItemCount() {
return headerViews.size();
}

/**
* 创建头部View或底部View的ViewHolder
*
* @param view 头部View或底部View
* @return ViewHolder
*/
private GeneralWrapRecyclerHolder createHeaderFooterViewHolder(View view) {
return new GeneralWrapRecyclerHolder(view) {
};
}

/**
* 判断是否是头部View
*
* @param key Key
* @return 是否是头部View
*/
private boolean isHeaderViewType(int key) {
return headerViews.indexOfKey(key) > -1;
}

/**
* 判断是否是底部View
*
* @param key Key
* @return 是否是底部View
*/
private boolean isFooterViewType(int key) {
return footerViews.indexOfKey(key) > -1;
}

/**
* 根据索引判断该位置的View是否是头部View
*
* @param position 索引
* @return 是否是头部View
*/
private boolean isHeaderPosition(int position) {
return (position > -1) && (position < headerViews.size());
}

/**
* 根据索引判断该位置的View是否是底部View
*
* @param position 索引
* @return 是否是底部View
*/
private boolean isFooterPosition(int position) {
return (position >= (headerViews.size() + getDataItemCount())) &&
(position < (headerViews.size() + getDataItemCount() + footerViews.size()));
}

/**
* 添加头部View
*
* @param view 头部View
*/
public void addHeaderView(View view) {
if (headerViews.indexOfValue(view) < 0) {
headerViews.put(BASE_ITEM_TYPE_HEADER++, view);
notifyDataSetChanged();
}
}

/**
* 添加底部View
*
* @param view 底部View
*/
public void addFooterView(View view) {
if (footerViews.indexOfValue(view) < 0) {
footerViews.put(BASE_ITEM_TYPE_FOOTER++, view);
notifyDataSetChanged();
}
}

/**
* 移除头部View
*
* @param view View
*/
public void removeHeaderView(View view) {
int index = headerViews.indexOfValue(view);
if (index > -1) {
headerViews.removeAt(index);
notifyDataSetChanged();
}
}

/**
* 移除底部View
*
* @param view View
*/
public void removeFooterView(View view) {
int index = footerViews.indexOfValue(view);
if (index > -1) {
footerViews.removeAt(index);
notifyDataSetChanged();
}
}

}


三、GeneralWrapRecyclerView

/**
* 作者: 叶应是叶
* 时间: 2017/6/4
* 描述: 可以带头部View与尾部View的RecyclerView
*/
public class GeneralWrapRecyclerView extends RecyclerView {

private GeneralWrapRecyclerAdapter mRecyclerAdapter;

public GeneralWrapRecyclerView(Context context) {
super(context);
}

public GeneralWrapRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public GeneralWrapRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

public void setAdapter(GeneralWrapRecyclerAdapter recyclerAdapter) {
this.mRecyclerAdapter = recyclerAdapter;
super.setAdapter(recyclerAdapter);
}

@Override
public void setAdapter(Adapter adapter) {

}

/**
* 添加头部View
*
* @param view View
*/
public void addHeaderView(View view) {
if (mRecyclerAdapter != null) {
mRecyclerAdapter.addHeaderView(view);
} else {
throw new RuntimeException("GeneralRecyclerAdapter == null");
}
}

/**
* 添加底部View
*
* @param view View
*/
public void addFooterView(View view) {
if (mRecyclerAdapter != null) {
mRecyclerAdapter.addFooterView(view);
} else {
throw new RuntimeException("GeneralRecyclerAdapter == null");
}
}

/**
* 移除头部View
*
* @param view View
*/
public void removeHeaderView(View view) {
if (mRecyclerAdapter != null) {
mRecyclerAdapter.removeHeaderView(view);
} else {
throw new RuntimeException("GeneralRecyclerAdapter == null");
}
}

/**
* 移除底部View
*
* @param view View
*/
public void removeFooterView(View view) {
if (mRecyclerAdapter != null) {
mRecyclerAdapter.removeFooterView(view);
} else {
throw new RuntimeException("GeneralRecyclerAdapter == null");
}
}

}


四、实际使用

这里在为 GeneralWrapRecyclerView 设置 Adapter 时就只能将参数值设置为 GeneralWrapRecyclerAdapter 类的对象了

public class GeneralWrapRecyclerActivity extends AppCompatActivity implements GeneralWrapRecyclerHolder.onClickCommonListener, View.OnClickListener {

private List<Data> dataList;

private List<View> headerViewList;

private List<View> footerViewList;

private GeneralWrapRecyclerView generalWrapRecyclerView;

private MyGeneralWrapRecyclerAdapter myGeneralWrapRecyclerAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_general_wrap_recycler);
initData();
generalWrapRecyclerView = (GeneralWrapRecyclerView) findViewById(R.id.rv_testRecyclerView);
generalWrapRecyclerView.setLayoutManager(new LinearLayoutManager(this));
myGeneralWrapRecyclerAdapter = new MyGeneralWrapRecyclerAdapter(this, dataList, R.layout.item, this);
generalWrapRecyclerView.setAdapter(myGeneralWrapRecyclerAdapter);
View headerView1 = getLayoutInflater().inflate(R.layout.header_view, generalWrapRecyclerView, false);
View headerView2 = getLayoutInflater().inflate(R.layout.header_view, generalWrapRecyclerView, false);
View footerView1 = getLayoutInflater().inflate(R.layout.footer_view, generalWrapRecyclerView, false);
View footerView2 = getLayoutInflater().inflate(R.layout.footer_view, generalWrapRecyclerView, false);
generalWrapRecyclerView.addHeaderView(headerView1);
generalWrapRecyclerView.addHeaderView(headerView2);
generalWrapRecyclerView.addFooterView(footerView1);
generalWrapRecyclerView.addFooterView(footerView2);
headerViewList.add(headerView1);
headerViewList.add(headerView2);
footerViewList.add(footerView1);
footerViewList.add(footerView2);
findViewById(R.id.btn_addData).setOnClickListener(this);
findViewById(R.id.btn_deleteData).setOnClickListener(this);
findViewById(R.id.btn_addHeaderView).setOnClickListener(this);
findViewById(R.id.btn_deleteHeaderView).setOnClickListener(this);
findViewById(R.id.btn_addFooterView).setOnClickListener(this);
findViewById(R.id.btn_deleteFooterView).setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_addData:
Data data = new Data(R.mipmap.ic_launcher, "Hi");
dataList.add(data);
myGeneralWrapRecyclerAdapter.notifyDataSetChanged();
break;
case R.id.btn_deleteData:
if (dataList.size() > 0) {
dataList.remove(0);
}
myGeneralWrapRecyclerAdapter.notifyDataSetChanged();
break;
case R.id.btn_addHeaderView:
View headerView = getLayoutInflater().inflate(R.layout.header_view, generalWrapRecyclerView, false);
headerViewList.add(headerView);
generalWrapRecyclerView.addHeaderView(headerView);
break;
case R.id.btn_deleteHeaderView:
if (headerViewList.size() > 0) {
generalWrapRecyclerView.removeHeaderView(headerViewList.get(0));
headerViewList.remove(0);
}
break;
case R.id.btn_addFooterView:
View footerView = getLayoutInflater().inflate(R.layout.footer_view, generalWrapRecyclerView, false);
footerViewList.add(footerView);
generalWrapRecyclerView.addFooterView(footerView);
break;
case R.id.btn_deleteFooterView:
if (footerViewList.size() > 0) {
generalWrapRecyclerView.removeFooterView(footerViewList.get(0));
footerViewList.remove(0);
}
break;
}
}

private void initData() {
dataList = new ArrayList<>();
headerViewList = new ArrayList<>();
footerViewList = new ArrayList<>();
for (int i = 0; i < 50; i++) {
Data data = new Data(R.mipmap.ic_launcher_round, "Hi:" + i);
dataList.add(data);
}
}

@Override
public void onClick(int position) {
Toast.makeText(this, "点击:" + position, Toast.LENGTH_SHORT).show();
}

@Override
public void onLongClick(int position) {
Toast.makeText(this, "长按:" + position, Toast.LENGTH_SHORT).show();
}

}


运行效果:



这里提供代码下载:解析RecyclerView(3)——以更简单的方法实现带顶部View和底部View的RecyclerView

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: