从月薪3000到年薪60万。从专科生到深圳一线大厂。关注我就能达到大师级水平,这话我终于敢说了, 年薪60万不是梦!
请问:怎么可以把代码格式调整?我贴出来换格式了。你们直接去Github下载工程!
今天开始讲RecycleView的系列教程。分割线,分组,局部刷新,动态添加,缓存原理,抖音效果,瀑布流。嵌套,动画等等
实现方案一:RecyclerView实现添加HeaderView和FooterView的核心就是在Adapter里面的onCreateViewHolder根据viewType来判断是列表项还是HeaderView来分别加载不同的布局文件。
bug:添加头部之后没法进行局部刷新。有bug
原因:添加头和尾部之后,position就变了!!!
实现方案二: 装饰设计模式:传入一个引用,让它的功能变的更强!!!!
比如:文件流读取:fileInputstream -----inpuststeeam
模仿listView添加头部和尾部
重点:
1.adapter套一层adapter
2.自定义recycleView
3.通过观察者模式监听
mAdapter =new MyRecycleViewAdapter(mList);
mRecyAttendanceAdapter =new WrapRecyclerAdapter(mAdapter);
private void initView() {
mRecyclerView = findViewById(R.id.rv_list);
mLinearLayoutManager =new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
//设置布局管理器
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mAdapter =new MyRecycleViewAdapter(mList);
mRecyAttendanceAdapter =new WrapRecyclerAdapter(mAdapter);
// 设置适配器
mRecyclerView.setAdapter(mRecyAttendanceAdapter);
// 实例化头部View
View headerView = LayoutInflater.from(this).inflate(R.layout.header, mRecyclerView, false);
// 添加头部
mRecyclerView.addHeaderView(headerView);
mAdapter.setOnItemClickListener(new RecyAttendanceAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
mAdapter.removeItem(position);
Toast.makeText(MyHeadActivity.this, "position:" + position, Toast.LENGTH_LONG);
}
@Override
public void onItemLongClick(View view, int position) {
}
});
}
public class WrapRecyclerAdapterextends RecyclerView.Adapter {
private final static StringTAG ="WrapRecyclerAdapter";
// 用来存放底部和头部View的集合 比Map要高效一些
// 可以点击进入看一下官方的解释
/**
* SparseArrays map integers to Objects. Unlike a normal array of Objects,
* there can be gaps in the indices. It is intended to be more memory efficient
* than using a HashMap to map Integers to Objects, both because it avoids
* auto-boxing keys and its data structure doesn't rely on an extra entry object
* for each mapping.
*/
private SparseArraymHeaderViews;
private SparseArraymFooterViews;
// 基本的头部类型开始位置 用于viewType
private static int BASE_ITEM_TYPE_HEADER =10000000;
// 基本的底部类型开始位置 用于viewType
private static int BASE_ITEM_TYPE_FOOTER =20000000;
// 列表的Adapter
private RecyclerView.AdaptermAdapter;
public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
this.mAdapter = adapter;
mHeaderViews =new SparseArray<>();
mFooterViews =new SparseArray<>();
}
@Override
public RecyclerView.ViewHolderonCreateViewHolder(ViewGroup parent, int viewType) {
// viewType 可能就是 SparseArray 的key
if (isHeaderViewType(viewType)) {
View headerView =mHeaderViews.get(viewType);
return createHeaderFooterViewHolder(headerView);
}
if (isFooterViewType(viewType)) {
View footerView =mFooterViews.get(viewType);
return createHeaderFooterViewHolder(footerView);
}
return mAdapter.onCreateViewHolder(parent, viewType);
}
/**
* 是不是底部类型
*/
private boolean isFooterViewType(int viewType) {
int position =mFooterViews.indexOfKey(viewType);
return position >=0;
}
/**
* 创建头部或者底部的ViewHolder
*/
private RecyclerView.ViewHoldercreateHeaderFooterViewHolder(View view) {
return new RecyclerView.ViewHolder(view) {
};
}
/**
* 是不是头部类型
*/
private boolean isHeaderViewType(int viewType) {
int position =mHeaderViews.indexOfKey(viewType);
return position >=0;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (isHeaderPosition(position) || isFooterPosition(position)) {
return;
}
// 计算一下位置
position = position -mHeaderViews.size();
mAdapter.onBindViewHolder(holder, position);
}
@Override
public int getItemViewType(int position) {
if (isHeaderPosition(position)) {
// 直接返回position位置的key
return mHeaderViews.keyAt(position);
}
if (isFooterPosition(position)) {
// 直接返回position位置的key
position = position -mHeaderViews.size() -mAdapter.getItemCount();
return mFooterViews.keyAt(position);
}
// 返回列表Adapter的getItemViewType
position = position -mHeaderViews.size();
return mAdapter.getItemViewType(position);
}
/**
* 是不是底部位置
*/
private boolean isFooterPosition(int position) {
return position >= (mHeaderViews.size() +mAdapter.getItemCount());
}
/**
* 是不是头部位置
*/
private boolean isHeaderPosition(int position) {
return position
}
@Override
public int getItemCount() {
// 条数三者相加 = 底部条数 + 头部条数 + Adapter的条数
return mAdapter.getItemCount() +mHeaderViews.size() +mFooterViews.size();
}
/**
* 获取列表的Adapter
*/
private RecyclerView.AdaptergetAdapter() {
return mAdapter;
}
// 添加头部
public void addHeaderView(View view) {
int position =mHeaderViews.indexOfValue(view);
if (position <0) {
mHeaderViews.put(BASE_ITEM_TYPE_HEADER++, view);
}
notifyDataSetChanged();
}
// 添加底部
public void addFooterView(View view) {
int position =mFooterViews.indexOfValue(view);
if (position <0) {
mFooterViews.put(BASE_ITEM_TYPE_FOOTER++, view);
}
notifyDataSetChanged();
}
// 移除头部
public void removeHeaderView(View view) {
int index =mHeaderViews.indexOfValue(view);
if (index <0)return;
mHeaderViews.removeAt(index);
notifyDataSetChanged();
}
// 移除底部
public void removeFooterView(View view) {
int index =mFooterViews.indexOfValue(view);
if (index <0)return;
mFooterViews.removeAt(index);
notifyDataSetChanged();
}
/**
* 解决GridLayoutManager添加头部和底部不占用一行的问题
*
* @param recycler
* @version 1.0
*/
public void adjustSpanSize(RecyclerView recycler) {
if (recycler.getLayoutManager()instanceof GridLayoutManager) {
final GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager();
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
boolean isHeaderOrFooter =
isHeaderPosition(position) || isFooterPosition(position);
return isHeaderOrFooter ?layoutManager.getSpanCount() :1;
}
});
}
}
}
public class WrapRecyclerViewextends RecyclerView {
// 包裹了一层的头部底部Adapter
private WrapRecyclerAdaptermWrapRecyclerAdapter;
// 这个是列表数据的Adapter
private RecyclerView.AdaptermAdapter;
public WrapRecyclerView(Context context) {
super(context);
}
public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public WrapRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setAdapter(Adapter adapter) {
// 为了防止多次设置Adapter
if (mAdapter !=null) {
mAdapter.unregisterAdapterDataObserver(mDataObserver);
mAdapter =null;
}
this.mAdapter = adapter;
if (adapterinstanceof WrapRecyclerAdapter) {
mWrapRecyclerAdapter = (WrapRecyclerAdapter) adapter;
}else {
mWrapRecyclerAdapter =new WrapRecyclerAdapter(adapter);
}
super.setAdapter(mWrapRecyclerAdapter);
// 注册一个观察者
mAdapter.registerAdapterDataObserver(mDataObserver);
// 解决GridLayout添加头部和底部也要占据一行
mWrapRecyclerAdapter.adjustSpanSize(this);
}
// 添加头部
public void addHeaderView(View view) {
// 如果没有Adapter那么就不添加,也可以选择抛异常提示
// 让他必须先设置Adapter然后才能添加,这里是仿照ListView的处理方式
if (mWrapRecyclerAdapter !=null) {
mWrapRecyclerAdapter.addHeaderView(view);
}
}
// 添加底部
public void addFooterView(View view) {
if (mWrapRecyclerAdapter !=null) {
mWrapRecyclerAdapter.addFooterView(view);
}
}
// 移除头部
public void removeHeaderView(View view) {
if (mWrapRecyclerAdapter !=null) {
mWrapRecyclerAdapter.removeHeaderView(view);
}
}
// 移除底部
public void removeFooterView(View view) {
if (mWrapRecyclerAdapter !=null) {
mWrapRecyclerAdapter.removeFooterView(view);
}
}
private AdapterDataObservermDataObserver =new AdapterDataObserver() {
@Override
public void onChanged() {
if (mAdapter ==null)return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果
if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyDataSetChanged();
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
if (mAdapter ==null)return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果
if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemRemoved(positionStart);
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
if (mAdapter ==null)return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyItemMoved没效果
if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
if (mAdapter ==null)return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果
if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemChanged(positionStart);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
if (mAdapter ==null)return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果
if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemChanged(positionStart,payload);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
if (mAdapter ==null)return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyItemInserted没效果
if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemInserted(positionStart);
}
};
}
}
demo地址:https://github.com/pengcaihua123456/shennandadao