請(qǐng)問(wèn):簡(jiǎn)書怎么可以把代碼格式調(diào)整烹俗?我貼出來(lái)?yè)Q格式了爆侣。你們直接去Github下載工程!
今天開(kāi)始講RecycleView的系列教程幢妄。分割線兔仰,分組,局部刷新磁浇,動(dòng)態(tài)添加斋陪,緩存原理,抖音效果置吓,瀑布流无虚。嵌套,動(dòng)畫等等
實(shí)現(xiàn)方案一:RecyclerView實(shí)現(xiàn)添加HeaderView和FooterView的核心就是在Adapter里面的onCreateViewHolder根據(jù)viewType來(lái)判斷是列表項(xiàng)還是HeaderView來(lái)分別加載不同的布局文件衍锚。
bug:添加頭部之后沒(méi)法進(jìn)行局部刷新友题。有bug
原因:添加頭和尾部之后,position就變了4髦省6然隆!
實(shí)現(xiàn)方案二:? 裝飾設(shè)計(jì)模式:傳入一個(gè)引用告匠,讓它的功能變的更強(qiáng)8瓿!:笞ā划鸽!
比如:文件流讀取:fileInputstream -----inpuststeeam
模仿listView添加頭部和尾部
重點(diǎn):
1.adapter套一層adapter
2.自定義recycleView
3.通過(guò)觀察者模式監(jiān)聽(tīng)
mAdapter =new MyRecycleViewAdapter(mList);
mRecyAttendanceAdapter =new WrapRecyclerAdapter(mAdapter);
private void initView() {
mRecyclerView = findViewById(R.id.rv_list);
? ? mLinearLayoutManager =new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
? ? //設(shè)置布局管理器
? ? mRecyclerView.setLayoutManager(mLinearLayoutManager);
? ? mAdapter =new MyRecycleViewAdapter(mList);
? ? mRecyAttendanceAdapter =new WrapRecyclerAdapter(mAdapter);
? ? // 設(shè)置適配器
? ? mRecyclerView.setAdapter(mRecyAttendanceAdapter);
? ? // 實(shí)例化頭部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";
? ? // 用來(lái)存放底部和頭部View的集合? 比Map要高效一些
? ? // 可以點(diǎn)擊進(jìn)入看一下官方的解釋
? ? /**
* 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;
? ? // 基本的頭部類型開(kāi)始位置? 用于viewType
? ? private static int BASE_ITEM_TYPE_HEADER =10000000;
? ? // 基本的底部類型開(kāi)始位置? 用于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;
? ? }
/**
? ? * 創(chuàng)建頭部或者底部的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;
? ? ? ? }
// 計(jì)算一下位置
? ? ? ? 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() {
// 條數(shù)三者相加 = 底部條數(shù) + 頭部條數(shù) + Adapter的條數(shù)
? ? ? ? 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添加頭部和底部不占用一行的問(wèn)題
? ? *
? ? * @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;
? ? // 這個(gè)是列表數(shù)據(jù)的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) {
// 為了防止多次設(shè)置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);
? ? ? ? // 注冊(cè)一個(gè)觀察者
? ? ? ? mAdapter.registerAdapterDataObserver(mDataObserver);
? ? ? ? // 解決GridLayout添加頭部和底部也要占據(jù)一行
? ? ? ? mWrapRecyclerAdapter.adjustSpanSize(this);
? ? }
// 添加頭部
? ? public void addHeaderView(View view) {
// 如果沒(méi)有Adapter那么就不添加,也可以選擇拋異常提示
? ? ? ? // 讓他必須先設(shè)置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沒(méi)效果
? ? ? ? ? ? if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyDataSetChanged();
? ? ? ? }
@Override
? ? ? ? public void onItemRangeRemoved(int positionStart, int itemCount) {
if (mAdapter ==null)return;
? ? ? ? ? ? // 觀察者? 列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged沒(méi)效果
? ? ? ? ? ? if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemRemoved(positionStart);
? ? ? ? }
@Override
? ? ? ? public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
if (mAdapter ==null)return;
? ? ? ? ? ? // 觀察者? 列表Adapter更新 包裹的也需要更新不然列表的notifyItemMoved沒(méi)效果
? ? ? ? ? ? if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemMoved(fromPosition, toPosition);
? ? ? ? }
@Override
? ? ? ? public void onItemRangeChanged(int positionStart, int itemCount) {
if (mAdapter ==null)return;
? ? ? ? ? ? // 觀察者? 列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged沒(méi)效果
? ? ? ? ? ? if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemChanged(positionStart);
? ? ? ? }
@Override
? ? ? ? public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
if (mAdapter ==null)return;
? ? ? ? ? ? // 觀察者? 列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged沒(méi)效果
? ? ? ? ? ? if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemChanged(positionStart,payload);
? ? ? ? }
@Override
? ? ? ? public void onItemRangeInserted(int positionStart, int itemCount) {
if (mAdapter ==null)return;
? ? ? ? ? ? // 觀察者? 列表Adapter更新 包裹的也需要更新不然列表的notifyItemInserted沒(méi)效果
? ? ? ? ? ? if (mWrapRecyclerAdapter !=mAdapter)
mWrapRecyclerAdapter.notifyItemInserted(positionStart);
? ? ? ? }
};
}
}