阅读XRecyclerView源码三
2017-06-13 16:44
169 查看
学习目标
理解 XRecyclerView 对传入的 adapter 的封装过程
这是接着上两篇文章阅读XRecyclerView源码一 和 阅读XRecyclerView源码二,进一步对开源项目 XRecyclerView 进行具体阅读。
接着是根据当前
因为加入了
同样,还有重写
重写
在
在
因为 RecyclerView 有三种不同的 LayoutManager 可以设置,所以在添加完
如果是
还有几个需要重写的方法
同时重写
为了解决下拉刷新和 CollapsingToolbarLayout 的冲突,在onAttachedToWindow() 方法中
Github例子源码
理解 XRecyclerView 对传入的 adapter 的封装过程
这是接着上两篇文章阅读XRecyclerView源码一 和 阅读XRecyclerView源码二,进一步对开源项目 XRecyclerView 进行具体阅读。
概述
我们可以像使用ReccylerView一样正常的使用
XRecyclerView。在我们创建好自己的 adapter 对 XRecyclerView 进行绑定的时候,XRecyclerView 会对传入的 adapter 进行一次封装,
WrapAdapter就是它封装后的形式。
WrapAdapter 类
在该类中,创建一个构造方法,传入的参数是要进行封装的 adapter,同时对外暴露一个获取封前 adapter 的方法。private RecyclerView.Adapter adapter; public WrapAdapter(RecyclerView.Adapter adapter) { this.adapter = adapter; } public RecyclerView.Adapter getOriginalAdapter(){ return this.adapter; }
接着是根据当前
position,判断当前
item的
viewType。
isHeader()、
isFooter()和
isRefreshHeader()。
public boolean isHeader(int position) { return position >= 1 && position < mHeaderViews.size() + 1; } public boolean isFooter(int position) { if(loadingMoreEnabled) { return position == getItemCount() - 1; }else { return false; } } public boolean isRefreshHeader(int position) { return position == 0; } public int getHeadersCount() { return mHeaderViews.size(); }
因为加入了
headerView、
footView和
refreshHeaderView,所以在
getItemViewType()方法中,我们要根据具体位置设置不同的
itemViewType。
@Override public int getItemViewType(int position) { int adjPosition = position - (getHeadersCount() + 1); if (isRefreshHeader(position)) { return TYPE_REFRESH_HEADER; } if (isHeader(position)) { position = position - 1; return sHeaderTypes.get(position); } if (isFooter(position)) { return TYPE_FOOTER; } int adapterCount; if (adapter != null) { adapterCount = adapter.getItemCount(); if (adjPosition < adapterCount) { int type = adapter.getItemViewType(adjPosition); if(isReservedItemViewType(type)) { throw new IllegalStateException("XRecyclerView require itemViewType in adapter should be less than 10000 " ); } return type; } } return 0; }
同样,还有重写
getItemCount()方法
@Override public int getItemCount() { if(loadingMoreEnabled) { if (adapter != null) { return getHeadersCount() + adapter.getItemCount() + 2; } else { return getHeadersCount() + 2; } }else { if (adapter != null) { return getHeadersCount() + adapter.getItemCount() + 1; } else { return getHeadersCount() + 1; } } }
重写
getItemId()方法
@Override public long getItemId(int position) { if (adapter != null && position >= getHeadersCount() + 1) { int adjPosition = position - (getHeadersCount() + 1); if (adjPosition < adapter.getItemCount()) { return adapter.getItemId(adjPosition); } } return -1; }
在
onCreateViewHolder()中还是根据对应的
itemViewType返回相应的
ViewHolder。
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_REFRESH_HEADER) { return new SimpleViewHolder(mRefreshHeader); } else if (isHeaderType(viewType)) { return new SimpleViewHolder(getHeaderViewByType(viewType)); } else if (viewType == TYPE_FOOTER) { return new SimpleViewHolder(mFootView); } // 一般情况下还是使用封装前 adapter 的创建方法 return adapter.onCreateViewHolder(parent, viewType); }
在
onBindViewHolder()中,通过
isHeader()和
isRefreshHeader()方法跳过 headerView 和 refreshHeaderView 的位置,将其它 item 用封装前的 adapter 的 onBindViewHolder() 方法进行数据绑定。WrapAdapter 中也重写了 onBindViewHolder() 带三个参数的方法,但是不知道什么时候会用到。
@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (isHeader(position) || isRefreshHeader(position)) { return; } int adjPosition = position - (getHeadersCount() + 1); int adapterCount; if (adapter != null) { adapterCount = adapter.getItemCount(); if (adjPosition < adapterCount) { adapter.onBindViewHolder(holder, adjPosition); } } } // some times we need to override this @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position,List<Object> payloads) { if (isHeader(position) || isRefreshHeader(position)) { return; } int adjPosition = position - (getHeadersCount() + 1); int adapterCount; if (adapter != null) { adapterCount = adapter.getItemCount(); if (adjPosition < adapterCount) { if(payloads.isEmpty()){ adapter.onBindViewHolder(holder, adjPosition); } else{ adapter.onBindViewHolder(holder, adjPosition,payloads); } } } }
因为 RecyclerView 有三种不同的 LayoutManager 可以设置,所以在添加完
headerView、
footView和
refreshHeaderView的时候,还要防止因为
GridLayoutManager设置的
spanSize,导致它们的 item 跨度不能占满一行,完全显示。所以我们还需要下面的设置
@Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); if (manager instanceof GridLayoutManager) { final GridLayoutManager gridManager = ((GridLayoutManager) manager); gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return (isHeader(position) || isFooter(position) || isRefreshHeader(position)) ? gridManager.getSpanCount() : 1; } }); } adapter.onAttachedToRecyclerView(recyclerView); }
如果是
StaggeredGridLayoutManager,需要获取
StaggeredGridLayoutManager的
LayoutParams,然后通过 setFullSpan() 方法设置它的占位宽度。
@Override public void onViewAttachedToWindow(ViewHolder holder) { ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams(); if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams && (isHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition()) || isRefreshHeader(holder.getLayoutPosition()))) { ((StaggeredGridLayoutManager.LayoutParams) layoutParams).setFullSpan(true); } adapter.onViewAttachedToWindow(holder); }
还有几个需要重写的方法
@Override public void onDetachedFromRecyclerView(RecyclerView recyclerView) { adapter.onDetachedFromRecyclerView(recyclerView); } @Override public void onViewDetachedFromWindow(ViewHolder holder) { adapter.onViewDetachedFromWindow(holder); } @Override public void onViewRecycled(ViewHolder holder) { adapter.onViewRecycled(holder); } @Override public boolean onFailedToRecycleView(ViewHolder holder) { return adapter.onFailedToRecycleView(holder); } @Override public void unregisterAdapterDataObserver(AdapterDataObserver observer) { adapter.unregisterAdapterDataObserver(observer); } @Override public void registerAdapterDataObserver(AdapterDataObserver observer) { adapter.registerAdapterDataObserver(observer); }
setAdapter() 方法
把传入的adapter进行封装
// 对传入的 adapter 进行封装 @Override public void setAdapter(Adapter adapter) { mWrapAdapter = new WrapAdapter(adapter); // 进行封装 super.setAdapter(mWrapAdapter); // 设置封装的 adapter adapter.registerAdapterDataObserver(mDataObserver); // 通过封装前的 adapter 注册数据观察者,可具体操作用 mWrapAdapter mDataObserver.onChanged(); // 通知 adapter 变化 }
同时重写
getAdapter()方法
// 避免用户自己调用 getAdapter() 获得的是 WrapAdapter,引起 ClassCastException @Override public Adapter getAdapter() { if (mWrapAdapter != null) { return mWrapAdapter.getOriginalAdapter(); // 返回封装前的 adapter } else { return null; } }
DataObserver 类
这个类继承了RecyclerView.AdapterDataObserver,当注册该类的 adapter 内容发生变化时,该类中的
onChanged()方法会实时响应。在这个类中重写所有的方法,把方法中的调用都换成封装的 adapter。
// adapter 的数据变化观察者,mWrapAdapter 操作 private class DataObserver extends RecyclerView.AdapterDataObserver { @Override public void onChanged() { super.onChanged(); if (mWrapAdapter != null) { mWrapAdapter.notifyDataSetChanged(); } } @Override public void onItemRangeChanged(int positionStart, int itemCount) { // super.onItemRangeChanged(positionStart, itemCount); mWrapAdapter.notifyItemRangeChanged(positionStart,itemCount); } @Override public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { // super.onItemRangeChanged(positionStart, itemCount, payload); mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { // super.onItemRangeInserted(positionStart, itemCount); mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { // super.onItemRangeRemoved(positionStart, itemCount); mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount); } @Override public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { // super.onItemRangeMoved(fromPosition, toPosition, itemCount); mWrapAdapter.notifyItemMoved(fromPosition, toPosition); } }
为了解决下拉刷新和 CollapsingToolbarLayout 的冲突,在onAttachedToWindow() 方法中
@Override protected void onAttachedToWindow() { super.onAttachedToWindow(); //解决和CollapsingToolbarLayout冲突的问题 AppBarLayout appBarLayout = null; ViewParent p = getParent(); while (p != null) { if (p instanceof CoordinatorLayout) { break; } p = p.getParent(); } if(p instanceof CoordinatorLayout) { CoordinatorLayout coordinatorLayout = (CoordinatorLayout)p; final int childCount = coordinatorLayout.getChildCount(); for (int i = childCount - 1; i >= 0; i--) { final View child = coordinatorLayout.getChildAt(i); if(child instanceof AppBarLayout) { appBarLayout = (AppBarLayout)child; break; } } if(appBarLayout != null) { appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { @Override public void onStateChanged(AppBarLayout appBarLayout, State state) { appbarState = state; } }); } } }
Github例子源码
相关文章推荐
- Volley源码阅读——NetworkImageView
- 源码阅读 1 SimpleRatingView
- [Chrome源码阅读]2个重要的类RenderViewHost和TabStripModel
- 12.11 阅读android项目源码笔记-水波view,左右翻页三种实现,图片、文件加密
- 从setContentView开始的源码阅读
- lambda-view: JS源码阅读工具
- View绘制流程及源码解析(一)——performTraversals()源码分析 96 游骑兵810 关注 2017.02.01 11:07* 字数 5024 阅读 945评论 3喜欢 6 本篇文
- ViewFlow 源码阅读笔记(1)
- Universal-Image-Loader源码阅读(8)-core/imageaware/NonViewAware
- (源码阅读)我们经常用的setContentView(),到底做了什么。
- Yii2.0源码阅读-视图(View)渲染过程
- Universal-Image-Loader源码阅读(7)-core/imageaware/ImageViewAware
- [RK3288][Android7.1.2] Launcher3 源码阅读之step6:根据布局文件找到对应的自定义View
- usbview源码阅读与总结
- Universal-Image-Loader源码阅读(6)-core/imageaware/ViewAware
- 安卓 View 工作流程-Measure、 Layout、Draw 源码阅读
- 源码阅读分析 - View的Touch事件分发
- Linux下阅读源码的好工具Kscope
- DotText源码阅读(1)-调试
- DotText源码阅读(1)-调试