您的位置:首页 > 其它

阅读XRecyclerView源码三

2017-06-13 16:44 169 查看
学习目标

理解 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例子源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  开源项目