随着RecyclerView高度自定义的特性(没错,RecyclerView真的可以为所欲为!),越来越多的开发者选择使用RV进行开发,进而诞生了相关RV的很多框架,今天我要说的就是关注度很高的万能适配器BaseRecyclerViewAdapterHelper和一个支持多种View的加载框架XRefreshView。
本人在实际的开发过程中使用BaseRecyclerViewAdapterHelper(万能适配器)遇到了一个问题,就是做分页加载的时候,当加载更多数据不满一屏幕的时候,如果是调用loadMoreComplete()方法,会出现无限加载的情况。这个问题可以通过判断如果数据不满指定分页条数,就调用loadMoreEnd()方法结束加载更多:
if (current_size < page_size) {
//数据全部数据
adapter.loadMoreEnd();
} else {
adapter.loadMoreComplete();
}
但是这样就会存在一个问题,假如一次请求20条数据,但是这个20条数据并不够一屏时,就还是会出现无限加载的问题。因此我就想到了用XRefreshView框架实现上拉加载,随后又遇到了问题,因为XRefreshView有自己指定的Adapter,不能用万能适配器,因此又卡住了。最后我想到了解决办法,就是将两者结合,自己写一个Adapter继承XRefreshView的适配器BaseRecyclerAdapter。
思路:写一个类,继承自BaseRecyclerAdapter,并通过泛型指定ViewHolder和数据类型Bean,实现getAdapterItemCount()和onCreateViewHolder()方法。然后通过反射拿到ViewHolder,然后通过返回holder,在具体的实现类中来设置具体的数据。
先看一下效果图:
代码如下(Kotlin版本):
abstract class BaseTabRecyclerAdapter<VH : RecyclerView.ViewHolder, T> : BaseRecyclerAdapter<VH> {
private lateinit var data: List<T>
private var layoutId: Int = -1
private lateinit var listener: OnItemClickListener
private lateinit var longClickListener: OnItemLongClickListener
constructor(data: List<T>) {
this.data = data
}
constructor(layoutId: Int) {
this.layoutId = layoutId
}
constructor(data: List<T>, layoutId: Int) {
this.data = data
this.layoutId = layoutId
}
override fun getViewHolder(view: View?): VH {
return createBaseViewHolder(view!!)
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int, isItem: Boolean): VH {
if (this.layoutId == -1) {
IllegalArgumentException("The current layout is not set, please set the layout")
}
val rootView = LayoutInflater.from(parent?.context).inflate(layoutId, parent, false)
return createBaseViewHolder(rootView)
}
override fun getAdapterItemCount(): Int {
return data?.size
}
override fun onBindViewHolder(holder: VH, position: Int, isItem: Boolean) {
val t = data?.get(position)
bindClickListener(holder,position)
convert(holder, t)
}
open fun setItemViewId(layoutId: Int) {
this.layoutId = layoutId
}
/**
* 绑定监听
*/
private fun bindClickListener(holder: VH, position: Int) {
if (holder == null) return
val itemView = holder.itemView ?: return
//点击事件
if (listener != null)
itemView.setOnClickListener { listener.onItemClick(position) }
//长按事件
if (longClickListener != null)
itemView.setOnLongClickListener {
longClickListener.onItemLongClick(position)
true
}
}
/**
* 自己实现
*/
abstract fun convert(holder: VH, t: T)
/**
* 创建ViewHolder
*/
private fun createBaseViewHolder(view: View): VH {
var temp: Class<*>? = javaClass
var z: Class<*>? = null
while (z == null && null != temp) {
z = getInstancedGenericVHClass(temp)
temp = temp.superclass
}
val vh: VH?
// 泛型擦除会导致z为null
if (z == null) {
vh = BaseViewHolder(view) as VH
} else {
vh = createGenericVHInstance(z, view)
}
return vh ?: BaseViewHolder(view) as VH
}
private fun getInstancedGenericVHClass(z: Class<*>): Class<*>? {
val type = z.genericSuperclass
if (type is ParameterizedType) {
val types = type.actualTypeArguments
for (temp in types) {
if (temp is Class<*>) {
if (BaseViewHolder::class.java.isAssignableFrom(temp)) {
return temp
}
} else if (temp is ParameterizedType) {
val rawType = type.rawType
if (rawType is Class<*> && BaseViewHolder::class.java.isAssignableFrom(rawType)) {
return rawType
}
}
}
}
return null
}
private fun createGenericVHInstance(z: Class<*>, view: View): VH? {
try {
val constructor: Constructor<*>
// inner and unstatic class
if (z.isMemberClass && !Modifier.isStatic(z.modifiers)) {
constructor = z.getDeclaredConstructor(javaClass, View::class.java)
constructor.isAccessible = true
return constructor.newInstance(this, view) as VH
} else {
constructor = z.getDeclaredConstructor(View::class.java)
constructor.isAccessible = true
return constructor.newInstance(view) as VH
}
} catch (e: NoSuchMethodException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: InstantiationException) {
e.printStackTrace()
} catch (e: InvocationTargetException) {
e.printStackTrace()
}
return null
}
companion object {
open class BaseViewHolder(view: View) : RecyclerView.ViewHolder(view)
interface OnItemClickListener {
fun onItemClick(position: Int)
}
interface OnItemLongClickListener {
fun onItemLongClick(position: Int)
}
}
fun setOnItemClickListener(listener: OnItemClickListener) {
this.listener = listener
}
fun setOnItemLongClickListener(longClickListener: OnItemLongClickListener) {
this.longClickListener = longClickListener
}
}
这样就可以使用XRefreshView做上拉加载,下拉刷新的万能适配了。
简单的使用方式:
class TabAdapter(var context: Context, data: List<String>) : BaseQuickAdapter<String, TabAdapter.Companion.TabViewHolder>(R.layout.recycler_tab_item_layout,data) {
override fun convert(holder: TabViewHolder, p1: String?) {
holder.textView.text = p1
}
companion object {
class TabViewHolder(view: View) : BaseViewHolder(view) {
var textView: TextView = view.tv_item
}
}
}
在此要感谢XRefreshView和BaseRecyclerViewAdapterHelper的作者。
https://github.com/huxq17/XRefreshView
https://github.com/CymChad/BaseRecyclerViewAdapterHelper