basequickadapter详解_BaseQuickAdapter

用法

普通布局BaseQuickAdapter

BaseQuickAdapter homeAdapter = new BaseQuickAdapter(R.layout.home_item_view, mDataList){

@Override

protected void convert(BaseViewHolder helper, HomeItem item) {

helper.setText(R.id.text, item.getTitle());

helper.setImageResource(R.id.icon, item.getImageResource());

}

};

多布局BaseMultiItemQuickAdapter

数据源类型需要继承自MultiItemEntity,MultiItemEntity是一个接口

原理

BaseQuickAdapter实例化第一步当然是调用我们的构造方法:

public BaseQuickAdapter(int layoutResId, List data) {

this.mData = data == null ? new ArrayList() : data;

if (layoutResId != 0) {

this.mLayoutResId = layoutResId;

}

}

public BaseQuickAdapter(List data) {

this(0, data);

}

public BaseQuickAdapter(int layoutResId) {

this(layoutResId, null);

}

getItemViewType

@Override

public int getItemViewType(int position) {

if (getEmptyViewCount() == 1) {

boolean header = mHeadAndEmptyEnable && getHeaderLayoutCount() != 0;

switch (position) {

case 0:

if (header) {

return HEADER_VIEW;

} else {

return EMPTY_VIEW;

}

case 1:

if (header) {

return EMPTY_VIEW;

} else {

return FOOTER_VIEW;

}

case 2:

return FOOTER_VIEW;

default:

return EMPTY_VIEW;

}

}

//当RecyclerView在渲染一个新的itemView时,就会判断是不是需要调用加载更多回调,需要就调用

autoLoadMore(position);

int numHeaders = getHeaderLayoutCount();

if (position < numHeaders) {

return HEADER_VIEW;

} else {

int adjPosition = position - numHeaders;

int adapterCount = mData.size();

if (adjPosition < adapterCount) {

return getDefItemViewType(adjPosition);

} else {

adjPosition = adjPosition - adapterCount;

int numFooters = getFooterLayoutCount();

if (adjPosition < numFooters) {

return FOOTER_VIEW;

} else {

return LOADING_VIEW;

}

}

}

}

根据我们data的index值以及我们是否开启空视图之类的数据来决定在onCreateViewHolder中应该返回什么类型的viewHolder。

onCreateViewHolder

@Override

public K onCreateViewHolder(ViewGroup parent, int viewType) {

K baseViewHolder = null;

this.mContext = parent.getContext();

this.mLayoutInflater = LayoutInflater.from(mContext);

switch (viewType) {

case LOADING_VIEW:

baseViewHolder = getLoadingView(parent);

break;

case HEADER_VIEW:

baseViewHolder = createBaseViewHolder(mHeaderLayout);

break;

case EMPTY_VIEW:

baseViewHolder = createBaseViewHolder(mEmptyLayout);

break;

case FOOTER_VIEW:

baseViewHolder = createBaseViewHolder(mFooterLayout);

break;

default:

//创建BaseViewHolder或者其拓展的类

baseViewHolder = onCreateDefViewHolder(parent, viewType);

bindViewClickListener(baseViewHolder);

}

baseViewHolder.setAdapter(this);

return baseViewHolder;

}

protected K createBaseViewHolder(ViewGroup parent, int layoutResId) {

return createBaseViewHolder(getItemView(layoutResId, parent));

}

/**

* if you want to use subclass of BaseViewHolder in the adapter,

* you must override the method to create new ViewHolder.

*

* @param view view

* @return new ViewHolder

*/

protected K createBaseViewHolder(View view) {

Class temp = getClass();

Class z = null;

while (z == null && null != temp) {

z = getInstancedGenericKClass(temp);

temp = temp.getSuperclass();

}

K k = createGenericKInstance(z, view);

return null != k ? k : (K) new BaseViewHolder(view);

}

/**

* try to create Generic K instance

*

* @param z

* @param view

* @return

*/

private K createGenericKInstance(Class z, View view) {

try {

Constructor constructor;

String buffer = Modifier.toString(z.getModifiers());

String className = z.getName();

// inner and unstatic class

if (className.contains("$") && !buffer.contains("static")) {

constructor = z.getDeclaredConstructor(getClass(), View.class);

return (K) constructor.newInstance(this, view);

} else {

constructor = z.getDeclaredConstructor(View.class);

return (K) constructor.newInstance(view);

}

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return null;

}

getLayoutPosition

注意这里使用了ViewHolder的getLayoutPosition方法,此方法返回的pos值与onBindViewHolder方法传入的position值有可能不同。

注:获取的位置和用户目前在屏幕上看到的是一致的.

onBindViewHolder

/**

* To bind different types of holder and solve different the bind events

*

* @param holder

* @param positions

* @see #getDefItemViewType(int)

*/

@Override

public void onBindViewHolder(K holder, int positions) {

int viewType = holder.getItemViewType();

switch (viewType) {

case 0:

convert(holder, mData.get(holder.getLayoutPosition() - getHeaderLayoutCount()));

break;

case LOADING_VIEW:

mLoadMoreView.convert(holder);

break;

case HEADER_VIEW:

break;

case EMPTY_VIEW:

break;

case FOOTER_VIEW:

break;

default:

convert(holder, mData.get(holder.getLayoutPosition() - getHeaderLayoutCount()));

break;

}

}

添加Header和Footer

默认的recycleview是没有addheaderView和addfooterview的,需要自定义

添加header(footer原理一样)

//添加Header对应的View

View view = getLayoutInflater().inflate(R.layout.head_view, (ViewGroup) mRecyclerView.getParent(), false);

//添加Header对应的点击事件

view.setOnClickListener(listener);

//调用BaseQuickAdapter

headerAndFooterAdapter.addHeaderView(headerView);

//(0,header.child)属于正常,其他情况下默认添加到head末尾

public int addHeaderView(View header) {

return addHeaderView(header, -1);

}

public int addHeaderView(View header, int index) {

return addHeaderView(header, index, LinearLayout.VERTICAL);

}

public int addHeaderView(View header, int index, int orientation) {

//如果没有header的话就新增一个HeaderLayout

if (mHeaderLayout == null) {

mHeaderLayout = new LinearLayout(header.getContext());

if (orientation == LinearLayout.VERTICAL) {

mHeaderLayout.setOrientation(LinearLayout.VERTICAL);

mHeaderLayout.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));

} else {

mHeaderLayout.setOrientation(LinearLayout.HORIZONTAL);

mHeaderLayout.setLayoutParams(new LayoutParams(WRAP_CONTENT, MATCH_PARENT));

}

}

//获取mHeaderLayout中的header个数

final int childCount = mHeaderLayout.getChildCount();

//如果index的小于0的话,表示插入在最前面index置为view的个数

//如果index大于childcount,index置为子view的个数

//校验index数据的正确性(0,index)往中间插入

if (index < 0 || index > childCount) {

index = childCount;

}

//将数据插入到headerlayout中

mHeaderLayout.addView(header, index);

//如果有一个header的话

if (mHeaderLayout.getChildCount() == 1) {

//获取新增的header的位置position为0

int position = getHeaderViewPosition();

if (position != -1) {

//通知插入一个数据位置0处

notifyItemInserted(position);

}

}

return index;

}

加载更多

使用

pullToRefreshAdapter.setOnLoadMoreListener(this, mRecyclerView);

pullToRefreshAdapter.setLoadMoreView(new CustomLoadMoreView());

pullToRefreshAdapter.setEnableLoadMore(true);

然后在网络请求,

请求成功的话调用loadMoreComplete()

将数据加载到RecycleView中去

请求失败的话调用loadMoreFail()

@Override

public void onLoadMoreRequested() {

//加载更多的请求

mSwipeRefreshLayout.setEnabled(false);

if (pullToRefreshAdapter.getData().size() < PAGE_SIZE) {

pullToRefreshAdapter.loadMoreEnd(true);

} else {

if (mCurrentCounter >= TOTAL_COUNTER) {

pullToRefreshAdapter.loadMoreEnd(mLoadMoreEndGone);//true is gone,false is visible

} else {

new Handler().postDelayed(new Runnable() {

@Override

public void run() {

pullToRefreshAdapter.addData(DataServer.getSampleData(PAGE_SIZE));

mCurrentCounter = pullToRefreshAdapter.getData().size();

pullToRefreshAdapter.loadMoreComplete();

mSwipeRefreshLayout.setEnabled(true);

}

},1000);

}

}

}

原理分析

添加loadermoreview项

/**

* Set the enabled state of load more.

*

* @param enable True if load more is enabled, false otherwise.

*/

public void setEnableLoadMore(boolean enable) {

int oldLoadMoreCount = getLoadMoreViewCount();

mLoadMoreEnable = enable;

int newLoadMoreCount = getLoadMoreViewCount();

//oldLoadMoreCount 代表在改变这个开关时我们是否处于显示上拉加载的view的状态,1表示处于该状态。

//newLoadMoreCount 代表我们当前是否可以开启上拉加载功能,同样,1表示可以。

if (oldLoadMoreCount == 1) {

//加入当前处于显示加载更多view的状态,移除加载更多view。

if (newLoadMoreCount == 0) {

notifyItemRemoved(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());

}

} else {

//开启上拉加载

if (newLoadMoreCount == 1) {

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);

notifyItemInserted(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());

}

}

}

当绘制view的时候当绘制到底部的时候会添加回调

显示LoadingView

private void autoLoadMore(int position) {

//只有开启了上拉加载且loadMoreView没有gone且data.size>0 ,且设置了mRequestLoadMoreListener时返回1

if (getLoadMoreViewCount() == 0) {

return;

}

/*

理解起来大概是这样的,mAutoLoadMoreSize是标识开启自动加载更多的一个数量阀值。这个返回很巧妙。

假设你的data.size =20 ,mAutoLoadMoreSize =10,当前position=9, 按照理解,这个pisition=9是个临界值,因为我们设置了剩余数量<10个时自动加载更多,此时计算9<20-10,position等于9,说明后面还有10个数据没渲染,当position=10时(未加载数据还剩9个,此时应该预加载更多),10<20-10,不成立,代码继续往下走,

执行

*/

if (position < getItemCount() - mAutoLoadMoreSize) {

return;

}

//当你快速上滑时,由于position>=10后满足条件,执行加载更多的回调,position=11时也会执行,以此类推,那么你将收到多次加载更多的回调。所以我们需要判断此时是否当前的加载更能多回调已完成,保证每次到达阀值后只调用一次加载更多回调方法。

if (mLoadMoreView.getLoadMoreStatus() != LoadMoreView.STATUS_DEFAULT) {

return;

}

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_LOADING);

if (!mLoading) {

mLoading = true;

if (getRecyclerView() != null) {

getRecyclerView().post(new Runnable() {

@Override

public void run() {

mRequestLoadMoreListener.onLoadMoreRequested();

}

});

} else {

mRequestLoadMoreListener.onLoadMoreRequested();

}

}

}

加载失败调用,可能你有需求在加载失败后要显示一个加载失败的view提示用户,而不是直接关闭loadMoreView。此时你可以调用该方法。

/**

* Refresh failed

*/

public void loadMoreFail() {

if (getLoadMoreViewCount() == 0) {

return;

}

mLoading = false;

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_FAIL);

notifyItemChanged(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());

}

/**

* Refresh end, no more data

*

* @param gone if true gone the load more view

*/

public void loadMoreEnd(boolean gone) {

if (getLoadMoreViewCount() == 0) {

return;

}

mLoading = false;

mNextLoadEnable = false;

mLoadMoreView.setLoadMoreEndGone(gone);

if (gone) {

notifyItemRemoved(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());

} else {

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_END);

notifyItemChanged(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount());

}

}

EmptyView设置

调用setEmptyView()

源码

public void setEmptyView(View emptyView) {

boolean insert = false;

if (mEmptyLayout == null) {

mEmptyLayout = new FrameLayout(emptyView.getContext());

final LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);

final ViewGroup.LayoutParams lp = emptyView.getLayoutParams();

if (lp != null) {

layoutParams.width = lp.width;

layoutParams.height = lp.height;

}

mEmptyLayout.setLayoutParams(layoutParams);

insert = true;

}

mEmptyLayout.removeAllViews();

mEmptyLayout.addView(emptyView);

mIsUseEmpty = true;

if (insert) {

if (getEmptyViewCount() == 1) {

int position = 0;

if (mHeadAndEmptyEnable && getHeaderLayoutCount() != 0) {

position++;

}

notifyItemInserted(position);

}

}

}

mEmptyLayout赋值

应该只有空数据(EmptyView,Header,Footer等等)

会执行getItemViewType来显示EmptyView

if (getEmptyViewCount() == 1) {

boolean header = mHeadAndEmptyEnable && getHeaderLayoutCount() != 0;

switch (position) {

case 0:

if (header) {

return HEADER_VIEW;

} else {

return EMPTY_VIEW;

}

case 1:

if (header) {

return EMPTY_VIEW;

} else {

return FOOTER_VIEW;

}

case 2:

return FOOTER_VIEW;

default:

return EMPTY_VIEW;

}

}

当有数据的时候

getEmptyViewCount()就为0,不会显示Empty数据

BaseMultiItemQuickAdapter多布局实现

使用

实体必须继承自MultiItemEntity

然后添加类型

addItemType(MultipleItem.TEXT, R.layout.item_text_view);

addItemType(MultipleItem.IMG, R.layout.item_image_view);

addItemType(MultipleItem.IMG_TEXT, R.layout.item_img_text_view);

在getItemViewType中会

protected int getDefItemViewType(int position) {

if (mMultiTypeDelegate != null) {

return mMultiTypeDelegate.getDefItemViewType(mData, position);

}

return super.getItemViewType(position);

}

返回类型type

在onCreateViewHolder中会调用

protected K onCreateDefViewHolder(ViewGroup parent, int viewType) {

int layoutId = mLayoutResId;

if (mMultiTypeDelegate != null) {

layoutId = mMultiTypeDelegate.getLayoutId(viewType);

}

return createBaseViewHolder(parent, layoutId);

}

根据viewtype获取到不同的layout

使用的是SparseArray存储的layout

protected K createBaseViewHolder(ViewGroup parent, int layoutResId) {

return createBaseViewHolder(getItemView(layoutResId, parent));

}

点击事件

SimpleClickListener实现

注:点击事件的实现有多重方式,如:

1,使用 RecyclerView提供的 addOnItemTouchListener()实现

2,创建 ItemView时添加点击事件监听

3,在 ItemView attach RecyclerView时实现

根据SDK中的解释,在Recyclerview 进行添加、移除item等操作时,position位置可能会变化,而所有的adapter的刷新并不总是及时的,只有这个方法返回的才是当前item经过一些变换后所处的真正位置。

使用

adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {

@Override

public void onItemClick(BaseQuickAdapter adapter, View view, int position) {

Log.d(TAG, "onItemClick: ");

Toast.makeText(ItemClickActivity.this, "onItemClick" + position, Toast.LENGTH_SHORT).show();

}

});

源码

/**

* Interface definition for a callback to be invoked when an itemchild in this

* view has been clicked

*/

public interface OnItemChildClickListener {

/**

* callback method to be invoked when an item in this view has been

* click and held

*

* @param view The view whihin the ItemView that was clicked

* @param position The position of the view int the adapter

*/

void onItemChildClick(BaseQuickAdapter adapter, View view, int position);

}

/**

* Interface definition for a callback to be invoked when an childView in this

* view has been clicked and held.

*/

public interface OnItemChildLongClickListener {

/**

* callback method to be invoked when an item in this view has been

* click and held

*

* @param view The childView whihin the itemView that was clicked and held.

* @param position The position of the view int the adapter

* @return true if the callback consumed the long click ,false otherwise

*/

boolean onItemChildLongClick(BaseQuickAdapter adapter, View view, int position);

}

/**

* Interface definition for a callback to be invoked when an item in this

* view has been clicked and held.

*/

public interface OnItemLongClickListener {

/**

* callback method to be invoked when an item in this view has been

* click and held

*

* @param adapter the adpater

* @param view The view whihin the RecyclerView that was clicked and held.

* @param position The position of the view int the adapter

* @return true if the callback consumed the long click ,false otherwise

*/

boolean onItemLongClick(BaseQuickAdapter adapter, View view, int position);

}

/**

* Interface definition for a callback to be invoked when an item in this

* RecyclerView itemView has been clicked.

*/

public interface OnItemClickListener {

/**

* Callback method to be invoked when an item in this RecyclerView has

* been clicked.

*

* @param adapter the adpater

* @param view The itemView within the RecyclerView that was clicked (this

* will be a view provided by the adapter)

* @param position The position of the view in the adapter.

*/

void onItemClick(BaseQuickAdapter adapter, View view, int position);

}

/**

* Register a callback to be invoked when an item in this RecyclerView has

* been clicked.

*

* @param listener The callback that will be invoked.

*/

public void setOnItemClickListener(@Nullable OnItemClickListener listener) {

mOnItemClickListener = listener;

}

/**

* Register a callback to be invoked when an itemchild in View has

* been clicked

*

* @param listener The callback that will run

*/

public void setOnItemChildClickListener(OnItemChildClickListener listener) {

mOnItemChildClickListener = listener;

}

/**

* Register a callback to be invoked when an item in this RecyclerView has

* been long clicked and held

*

* @param listener The callback that will run

*/

public void setOnItemLongClickListener(OnItemLongClickListener listener) {

mOnItemLongClickListener = listener;

}

/**

* Register a callback to be invoked when an itemchild in this View has

* been long clicked and held

*

* @param listener The callback that will run

*/

public void setOnItemChildLongClickListener(OnItemChildLongClickListener listener) {

mOnItemChildLongClickListener = listener;

}

/**

* @return The callback to be invoked with an item in this RecyclerView has

* been long clicked and held, or null id no callback as been set.

*/

public final OnItemLongClickListener getOnItemLongClickListener() {

return mOnItemLongClickListener;

}

/**

* @return The callback to be invoked with an item in this RecyclerView has

* been clicked and held, or null id no callback as been set.

*/

public final OnItemClickListener getOnItemClickListener() {

return mOnItemClickListener;

}

/**

* @return The callback to be invoked with an itemchild in this RecyclerView has

* been clicked, or null id no callback has been set.

*/

@Nullable

public final OnItemChildClickListener getOnItemChildClickListener() {

return mOnItemChildClickListener;

}

/**

* @return The callback to be invoked with an itemChild in this RecyclerView has

* been long clicked, or null id no callback has been set.

*/

@Nullable

public final OnItemChildLongClickListener getmOnItemChildLongClickListener() {

return mOnItemChildLongClickListener;

}

设置了4个接口的回调

在onCreateViewHolder方法中回调了

bindViewClickListener(baseViewHolder);

设置单击和回调事件

private void bindViewClickListener(final BaseViewHolder baseViewHolder) {

if (baseViewHolder == null) {

return;

}

final View view = baseViewHolder.getConvertView();

if (view == null) {

return;

}

view.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

if (getOnItemClickListener() != null && baseViewHolder != null) {

getOnItemClickListener().onItemClick(BaseQuickAdapter.this, v, baseViewHolder.getLayoutPosition() - getHeaderLayoutCount());

}

}

});

view.setOnLongClickListener(new View.OnLongClickListener() {

@Override

public boolean onLongClick(View v) {

if (getOnItemLongClickListener() != null && baseViewHolder != null) {

return getOnItemLongClickListener().onItemLongClick(BaseQuickAdapter.this, v, baseViewHolder.getLayoutPosition() - getHeaderLayoutCount());

}

return false;

}

});

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值