由于项目需要移除 support 库,需要将 Bravh 从 2.x 迁移到 3.x ,废话不多说直接看差异
导包地址差异
Bravh 2.x
com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.50
Bravh 3.x
io.github.cymchad:BaseRecyclerViewAdapterHelper:3.0.14
代码差异
BaseViewHolder
-
helper.setGone(id, isGone) isGone参数含义与2.x相反 ,true为不可见,false为可见 -
2.x
setBackgroundRes替换成setBackgroundResource -
2.x
setNestView移除,这个后面点击事件会提到
还有很多移除的 Api,等待你们自己去发现懒得写了。也给大家来了个处理差异的方案文章最后自取
MultipleItemRvAdapter
2.x 版本的 MultipleItemRvAdapter 3.x 上替换为 BaseProviderMultiAdapter。这个地方有点骚,新版本默认使用的 BaseViewHolder。唉,setGone 刚好相反还不让你自定义,你气不气 。莫名又奖励了一堆 bug
给大家来了个处理差异的方案文章最后自取
BaseSectionQuickAdapter
2.x 版本 BaseSectionQuickAdapter 和 3.x 版本上的差异如下
2.x 版本
public BaseSectionQuickAdapter(int layoutResId, int sectionHeadResId, List<T> data) {
super(layoutResId, data);
this.mSectionHeadResId = sectionHeadResId;
}
3.x 版本
abstract class BaseSectionQuickAdapter<T : SectionEntity, VH : BaseViewHolder>
@JvmOverloads constructor(@LayoutRes private val sectionHeadResId: Int,
data: MutableList<T>? = null)
: BaseMultiItemQuickAdapter<T, VH>(data) {
constructor(
@LayoutRes sectionHeadResId: Int,
@LayoutRes layoutResId: Int,
data: MutableList<T>? = null
) : this(sectionHeadResId, data) {
setNormalLayout(layoutResId)
}
}
注意:
sectionHeadResId和layoutResId。我不懂,但是我大受震撼。
Adapter 点击事件
2.x 版本
holder.addOnClickListener(viewId)
holder.addOnLongClickListener(viewId)
3.x 版本,初始化的时候即可调用 setNestView 需要自己处理下
addChildClickViewIds(viewIds)
addChildLongClickViewIds(viewIds)
这边有一个坑点:文章写完后三天发现的
MultipleItemRvAdapter 这个 Adapter 的子控件点击事件有点特殊
设置了 Adapter 的 setOnChildViewClickListener 需要 addChildClickViewIds(viewIds) 需要写在 adapter 中才会响应,写在 BaseItemProvider 中不生效。
如果没有设置 setOnChildViewClickListener 并且 addChildClickViewIds(viewIds) 写在了 BaseItemProvider 中会回调 ItemProvider 的这个方法
override fun onChildClick(helper: BaseDefViewHolder, view: View, data: T, position: Int) {
super.onChildClick(helper, view, data, position)
}
Adapter 加载更多
2.x 加载更多在 3.x BaseQuickAdapter 需要实现 LoadMoreModule 接口,然后外面监听需如下改动
adapter.getLoadMoreModule().setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
page++;
getDataBatch();
}
});
adapter.getLoadMoreModule().setAutoLoadMore(true);
// 当自动加载开启,同时数据不满一屏时,是否继续执行自动加载更多(默认为true)
adapter.getLoadMoreModule().setEnableLoadMoreIfNotFullPage(false);
smart_refresh.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
// 这里的作用是防止下拉刷新的时候还可以上拉加载
adapter.getLoadMoreModule().setEnableLoadMore(false);
page = 1;
getDataBatch();
}
});
if (pageInfo.isFirstPage()) {
//如果是加载的第一页数据,用 setData()
adapter.setList(data);
} else {
//不是第一页,则用add
adapter.addData(data);
}
if (data.size() < PAGE_SIZE) {
// 如果不够一页,显示没有更多数据布局
adapter.getLoadMoreModule().loadMoreEnd();
} else {
adapter.getLoadMoreModule().loadMoreComplete();
}
注意:
Adapter需要实现LoadMoreModule接口,否则会崩溃。这边后面有 kt 的扩展有需要的可以拿走
Adapter 拖拽功能
2.x BaseItemDraggableAdapter 在 3.x 上使用 BaseSectionQuickAdapter 并且 Adapter 需要实现 DraggableModule,以前内置的拖拽回调需要实现 OnItemDragListener 接口
3.x 版本调用代码如下
adapter.draggableModule.run {
// 是否支持拽功能
isDragEnabled = true
// 支持拖拽指定控件 ID
toggleViewId = R.id.iv_options
// 这个必须在 toggleViewId 之后调用
isDragOnLongPressEnabled = true
}
其他
自己发现去吧,我只用到这么多
差异调整方案
加载更多 & upFetch 扩展
@JvmOverloads
fun BaseQuickAdapter<*, *>?.initLoadMore(view: BaseLoadMoreView? = null, loadMoreCall: OnLoadMoreListener) {
checkIsLoadMoreAdapter {
isAutoLoadMore = true
view?.let {
loadMoreView = it
}
isEnableLoadMore = true
setOnLoadMoreListener {
loadMoreCall.onLoadMore()
}
}
}
@JvmOverloads
fun BaseQuickAdapter<*, *>?.initUpFetch(enable: Boolean = true, position: Int, listener: OnUpFetchListener?) {
checkIsUpFetchAdapter {
isUpFetchEnable = enable
startUpFetchPosition = position
setOnUpFetchListener(listener)
}
}
@JvmOverloads
fun BaseQuickAdapter<*, *>?.loadMoreEnd(enable: Boolean? = null) {
checkIsLoadMoreAdapter {
loadMoreEnd()
enable?.let {
loadMoreEnable(enable)
}
}
}
fun BaseQuickAdapter<*, *>?.loadMoreComplete() {
checkIsLoadMoreAdapter {
loadMoreComplete()
}
}
fun BaseQuickAdapter<*, *>?.loadMoreFail() {
checkIsLoadMoreAdapter {
loadMoreFail()
}
}
fun BaseQuickAdapter<*, *>?.loadMoreEnable(enable: Boolean) {
checkIsLoadMoreAdapter {
isEnableLoadMore = enable
}
}
fun BaseQuickAdapter<*, *>?.upFetchEnable(enable: Boolean) {
checkIsUpFetchAdapter {
isUpFetchEnable = enable
}
}
fun BaseQuickAdapter<*, *>?.checkIsLoadMoreAdapter(callback: BaseLoadMoreModule.() -> Unit) {
(this as? LoadMoreModule)?.let {
callback.invoke(loadMoreModule)
} ?: if (BuildConfig.DEBUG) {
ToastHelper.showToastLong(applicationContext, "请让 adapter 实现 LoadMore 接口 $this")
}
}
// 对了这边还有个 UpFetch 的扩展看看就知道咋改了,不写了累了
fun BaseQuickAdapter<*, *>?.checkIsUpFetchAdapter(callback: BaseUpFetchModule.() -> Unit) {
(this as? UpFetchModule)?.let {
callback.invoke(upFetchModule)
} ?: if (BuildConfig.DEBUG) {
ToastHelper.showToastShort(applicationContext, "请让 adapter 实现 LoadMore 接口")
}
}
自定义 BaseDefViewHolder 解决 BaseViewHolder 差异问题
open class BaseDefViewHolder(view: View) : BaseViewHolder(view) {
override fun setGone(viewId: Int, isGone: Boolean): BaseViewHolder {
return super.setGone(viewId, !isGone)
}
}
fun setBackgroundRes(@IdRes viewId: Int, @DrawableRes backgroundRes: Int): BaseViewHolder {
setBackgroundResource(viewId, backgroundRes)
return this
}
有啥差异自己补一下吧,看看你需要哪些,全局替换 BaseViewHolder
MultipleItemRvAdapter 解决方案,不需要的后面不用看了没鸟用
BaseCommonItemProvider.kt 类
abstract class BaseCommonItemProvider<T, K : BaseViewHolder> {
lateinit var context: Context
private var weakAdapter: WeakReference<BaseCommonProviderMultiAdapter<T, K>>? = null
private val clickViewIds by lazy(LazyThreadSafetyMode.NONE) { ArrayList<Int>() }
private val longClickViewIds by lazy(LazyThreadSafetyMode.NONE) { ArrayList<Int>() }
internal fun setAdapter(adapter: BaseCommonProviderMultiAdapter<T, K>) {
weakAdapter = WeakReference(adapter)
}
open fun getAdapter(): BaseCommonProviderMultiAdapter<T, K>? {
return weakAdapter?.get()
}
abstract val itemViewType: Int
abstract val layoutId: Int
@LayoutRes
get
abstract fun convert(helper: K, item: T)
open fun convert(helper: K, item: T, payloads: List<Any>) {}
/**
* (可选重写)创建 ViewHolder。
* 默认实现返回[BaseViewHolder],可重写返回自定义 ViewHolder
*
* @param parent
*/
abstract fun onCreateViewHolder(parent: ViewGroup, viewType: Int): K
/**
* (可选重写)ViewHolder创建完毕以后的回掉方法。
* @param viewHolder VH
*/
open fun onViewHolderCreated(viewHolder: BaseViewHolder, viewType: Int) {}
/**
* Called when a view created by this [BaseItemProvider] has been attached to a window.
* 当此[BaseItemProvider]出现在屏幕上的时候,会调用此方法
*
* This can be used as a reasonable signal that the view is about to be seen
* by the user. If the [BaseItemProvider] previously freed any resources in
* [onViewDetachedFromWindow][.onViewDetachedFromWindow]
* those resources should be restored here.
*
* @param holder Holder of the view being attached
*/
open fun onViewAttachedToWindow(holder: BaseViewHolder) {}
/**
* Called when a view created by this [BaseItemProvider] has been detached from its
* window.
* 当此[BaseItemProvider]从屏幕上移除的时候,会调用此方法
*
* Becoming detached from the window is not necessarily a permanent condition;
* the consumer of an Adapter's views may choose to cache views offscreen while they
* are not visible, attaching and detaching them as appropriate.
*
* @param holder Holder of the view being detached
*/
open fun onViewDetachedFromWindow(holder: BaseViewHolder) {}
/**
* item 若想实现条目点击事件则重写该方法
* @param helper VH
* @param data T
* @param position Int
*/
open fun onClick(helper: K, view: View, data: T, position: Int) {}
/**
* item 若想实现条目长按事件则重写该方法
* @param helper VH
* @param data T
* @param position Int
* @return Boolean
*/
open fun onLongClick(helper: K, view: View, data: T, position: Int): Boolean {
return false
}
open fun onChildClick(helper: K, view: View, data: T, position: Int) {}
open fun onChildLongClick(helper: K, view: View, data: T, position: Int): Boolean {
return false
}
fun addChildClickViewIds(@IdRes vararg ids: Int) {
ids.forEach {
this.clickViewIds.add(it)
}
}
fun getChildClickViewIds() = this.clickViewIds
fun addChildLongClickViewIds(@IdRes vararg ids: Int) {
ids.forEach {
this.longClickViewIds.add(it)
}
}
fun getChildLongClickViewIds() = this.longClickViewIds
}
BaseCommonProviderMultiAdapter.kt 类
abstract class BaseCommonProviderMultiAdapter<T, K : BaseViewHolder>(data: MutableList<T>? = null) :
BaseQuickAdapter<T, K>(0, data) {
private val mItemProviders by lazy(LazyThreadSafetyMode.NONE) { SparseArray<BaseCommonItemProvider<T, K>>() }
/**
* 返回 item 类型
* @param data List<T>
* @param position Int
* @return Int
*/
protected abstract fun getItemType(data: List<T>, position: Int): Int
/**
* 必须通过此方法,添加 provider
* @param provider BaseItemProvider
*/
open fun addItemProvider(provider: BaseCommonItemProvider<T, K>) {
provider.setAdapter(this)
mItemProviders.put(provider.itemViewType, provider)
}
override fun onCreateDefViewHolder(parent: ViewGroup, viewType: Int): K {
val provider = getItemProvider(viewType)
checkNotNull(provider) { "ViewType: $viewType no such provider found,please use addItemProvider() first!" }
provider.context = parent.context
return provider.onCreateViewHolder(parent, viewType).apply {
provider.onViewHolderCreated(this, viewType)
}
}
override fun getDefItemViewType(position: Int): Int {
return getItemType(data, position)
}
override fun convert(holder: K, item: T) {
getItemProvider(holder.itemViewType)!!.convert(holder, item)
}
override fun convert(holder: K, item: T, payloads: List<Any>) {
getItemProvider(holder.itemViewType)!!.convert(holder, item, payloads)
}
override fun bindViewClickListener(viewHolder: K, viewType: Int) {
super.bindViewClickListener(viewHolder, viewType)
bindClick(viewHolder)
bindChildClick(viewHolder, viewType)
}
/**
* 通过 ViewType 获取 BaseItemProvider
* 例如:如果ViewType经过特殊处理,可以重写此方法,获取正确的Provider
* (比如 ViewType 通过位运算进行的组合的)
*
* @param viewType Int
* @return BaseItemProvider
*/
protected open fun getItemProvider(viewType: Int): BaseCommonItemProvider<T, K>? {
return mItemProviders.get(viewType)
}
override fun onViewAttachedToWindow(holder: K) {
super.onViewAttachedToWindow(holder)
getItemProvider(holder.itemViewType)?.onViewAttachedToWindow(holder)
}
override fun onViewDetachedFromWindow(holder: K) {
super.onViewDetachedFromWindow(holder)
getItemProvider(holder.itemViewType)?.onViewDetachedFromWindow(holder)
}
protected open fun bindClick(viewHolder: K) {
if (getOnItemClickListener() == null) {
//如果没有设置点击监听,则回调给 itemProvider
//Callback to itemProvider if no click listener is set
viewHolder.itemView.setOnClickListener {
var position = viewHolder.bindingAdapterPosition
if (position == RecyclerView.NO_POSITION) {
return@setOnClickListener
}
position -= headerLayoutCount
val itemViewType = viewHolder.itemViewType
val provider = mItemProviders.get(itemViewType)
provider.onClick(viewHolder, it, data[position], position)
}
}
if (getOnItemLongClickListener() == null) {
//如果没有设置长按监听,则回调给itemProvider
// If you do not set a long press listener, callback to the itemProvider
viewHolder.itemView.setOnLongClickListener {
var position = viewHolder.bindingAdapterPosition
if (position == RecyclerView.NO_POSITION) {
return@setOnLongClickListener false
}
position -= headerLayoutCount
val itemViewType = viewHolder.itemViewType
val provider = mItemProviders.get(itemViewType)
provider.onLongClick(viewHolder, it, data[position], position)
}
}
}
protected open fun bindChildClick(viewHolder: K, viewType: Int) {
if (getOnItemChildClickListener() == null) {
val provider = getItemProvider(viewType) ?: return
val ids = provider.getChildClickViewIds()
ids.forEach { id ->
viewHolder.itemView.findViewById<View>(id)?.let {
if (!it.isClickable) {
it.isClickable = true
}
it.setOnClickListener { v ->
var position: Int = viewHolder.bindingAdapterPosition
if (position == RecyclerView.NO_POSITION) {
return@setOnClickListener
}
position -= headerLayoutCount
provider.onChildClick(viewHolder, v, data[position], position)
}
}
}
}
if (getOnItemChildLongClickListener() == null) {
val provider = getItemProvider(viewType) ?: return
val ids = provider.getChildLongClickViewIds()
ids.forEach { id ->
viewHolder.itemView.findViewById<View>(id)?.let {
if (!it.isLongClickable) {
it.isLongClickable = true
}
it.setOnLongClickListener { v ->
var position: Int = viewHolder.bindingAdapterPosition
if (position == RecyclerView.NO_POSITION) {
return@setOnLongClickListener false
}
position -= headerLayoutCount
provider.onChildLongClick(viewHolder, v, data[position], position)
}
}
}
}
}
}
BaseDefItemProvider.kt 类
abstract class BaseDefItemProvider<T> : BaseCommonItemProvider<T, BaseDefViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseDefViewHolder {
return BaseDefViewHolder(parent.getItemView(layoutId))
}
}
BaseDefProviderMultiAdapter.kt 类
/**
* 由于 brvah 2.xx 迁移到 3.xx 部分 api 出现改动
* 例如: [com.chad.library.adapter.base.viewholder.BaseViewHolder] 中 setGone 方法和以前逻辑相反,导致所有调用处出现异常等等。
*
* [BaseDefViewHolder] 重写了 [com.chad.library.adapter.base.viewholder.BaseViewHolder] 处理 api 升级后导致的改动
*
* 提供 [BaseCommonProviderMultiAdapter] 支持自定义 BaseViewHolder
* 提供 [BaseDefProviderMultiAdapter] 默认使用 [BaseDefViewHolder] 来兼容新 api 的改动
*/
abstract class BaseDefProviderMultiAdapter<T>(data: MutableList<T>? = null) : BaseCommonProviderMultiAdapter<T, BaseDefViewHolder>(data)
原先继承
MultipleItemRvAdapter改成BaseCommonProviderMultiAdapter即可。继承
BaseItemProvider改成BaseDefItemProvider就可以了。不会因为
BaseViewHolder的 Api 改动出问题了