随着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