文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

BaseQuickAdapter的使用

2023-08-19 10:40

关注

是由BRVAH(官方网站)提供的万用适配器,相比原始的适配器,能减少70%的代码


简单需求实现:一个Adapter将数据和布局与RecyclerView绑定。
创建MyAdapter并继承BaseQuickAdapter,第一个泛型对应数据类型,就是ItemBean;第二个泛型对应ViewHolder,一般直接填写BaseViewHolder即可。

inner class MyAdapter(private val layoutRes: Int) :        BaseQuickAdapter<ItemBean, BaseViewHolder>(layoutRes) {        override fun convert(holder: BaseViewHolder, item: ItemBean) {            holder.setText(R.id.textView, "${ItemBean.text}")//先获取指定组件,再设置属性        }    }

convert方法类似原始适配器中的onBindViewHolder方法,用于绑定数据、设置事件等。
定义好了适配器,需要初始化recyclerview
//这个rv该设计为高复用性

        val layoutManager = LinearLayoutManager(this)        recyclerView.layoutManager = layoutManager        recyclerView.adapter = MyAdapter(R.layout.layout_list_item)

添加头部

//添加头部尾部布局        val footView: View =            LayoutInflater.from(this).inflate(R.layout.layout_foot, recyclerView, false)        adapter.setFooterView(footView)        val headView: View =            LayoutInflater.from(this).inflate(R.layout.layout_head, recyclerView, false)        adapter.setHeaderView(headView)

添加点击事件
点击事件的对象可以是Item条目,也可以是Item中的子控件,事件可以是点击或者长按。
添加Item子控件事件的方式有两种,一种是在Adapter的convert方法中获取控件,然后设置事件;另一种方式则与设置Item事件类似,不过需要先注册对应的控件。
第一种方式:在convert方法中设置

inner class MyAdapter(private val layoutRes: Int) :        BaseQuickAdapter<ItemBean, BaseViewHolder>(layoutRes) {        override fun convert(holder: BaseViewHolder, item: ItemBean) {            val rvClick = holder.getView<RelativeLayout>(R.id.RV)            rvClick.setOnClickListener {                //点击事件            }        }    }

第二种方式:使用adapter设置
首先注册对应控件

       adapter.addChildClickViewIds(R.id.editForm,R.id.editFormText)

//添加点击事件

    //RecyclerView的item点击事件        adapter.setOnItemClickListener { adapter, view, position ->            onItemClick(view,position)        }        //RecyclerView的item子控件点击事件        adapter.setOnItemChildClickListener { adapter, view, position ->            onItemChildClick(view,position)        }

通过回调获取监听事件

override fun onItemChildClick(view: View, position: Int) {        when(view.id){            R.id.editForm -> {                toast("editForm点击新增事件")            }            R.id.editFormText -> {                toast("editFormText点击事件")            }        }    }

注意:监听子控件点击事件对应的是 setOnItemChildClickListener ,若添加的是setOnItemClickListener 是获取不到的。
长按点击事件类似不在叙述。

添加动画

adapter.setAnimationWithDefault(AnimationType type)

//内置默认动画类型
enum class AnimationType {
AlphaIn, ScaleIn, SlideInBottom, SlideInLeft, SlideInRight
}

分组布局也是多布局的一种,比如分组为头布局和内容布局,而多布局则可以包含更多的布局。框架中,提供的对分组布局的解决方案是:BaseSectionQuickAdapter,提供的对多布局的解决方案有:BaseMultiItemQuickAdapter、BaseDelegateMultiAdapterBaseProviderMultiAdapter,它们各有优势,实际使用时根据不同的设计需求合理选择即可。

1.BaseMultiItemQuickAdapter

适用于类型较少,业务不复杂的场景,便于快速使用。 使用此适配器时,数据类必须实现MultiItemEntity接口并重写getItemType方法来返回类型。
定义数据类:

class BaseMultiQuickItem(override val itemType: Int, val data: BaseQuickerItem) : MultiItemEntity {     companion object {          const val FIRST_TYPE = 1          const val SECOND_TYPE = 2     }}

有了数据类之后,就可以着手编写适配器类了。适配器先将对应的布局和类型绑定,然后在convert方法中根据类型设置数据即可。

inner class BaseQuickInfoListAdapter :        BaseMultiItemQuickAdapter<BaseMultiQuickItem, BaseViewHolder>() {        init {        //为不同类型添加不同的布局            addItemType(BaseMultiQuickItem.FIRST_TYPE, R.layout.layout_base_quick_first_item)            addItemType(BaseMultiQuickItem.SECOND_TYPE , R.layout.layout_base_quick_second_item)        }        override fun convert(holder: BaseViewHolder, itemMulti: BaseMultiQuickItem) {            //多item            when(holder.itemViewType){                BaseMultiQuickItem.FIRST_TYPE  -> {                    holder.setText(R.id.formName, "${itemMulti.data.title}")                }                BaseMultiQuickItem.SECOND_TYPE  -> {                    holder.setText(R.id.formName, "第二個布局")                }            }        }    }

最后,为RecyclerView设置适配器即可。

在这里插入图片描述

2.BaseDelegateMultiAdapter

通过代理类的方式,返回布局id和item类型。此适配器的的数据类型可以为任意类型,适用于实体类不方便拓展的情况。 实体类仍使用 BaseMultiQuickItem,直接看适配器的实现。

class DelegateMultiAdapter :        BaseDelegateMultiAdapter<BaseMultiQuickItem?, BaseViewHolder>() {        //通过convert方法设置数据        override fun convert(helper: BaseViewHolder, item: BaseMultiQuickItem?) {            when (helper.itemViewType) {                BaseMultiQuickItem.FIRST_TYPE -> helper.setText(                    R.id.editForm,                    "FIRST_TYPE"                )                BaseMultiQuickItem.SECOND_TYPE -> {                    when (helper.layoutPosition % 2) {                        0 -> helper.setText(R.id.editForm, "SECOND_TYPE 111")                        1 -> helper.setText(R.id.editForm, "SECOND_TYPE 222")                        else -> {}                    }                }                else -> {}            }        }        init {            // 1、设置代理,通过setMultiTypeDelegate方法返回类型。            setMultiTypeDelegate(object : BaseMultiTypeDelegate<BaseMultiQuickItem?>() {                override fun getItemType(data: List<BaseMultiQuickItem?>, position: Int): Int {                    // 根据数据,自己判断应该返回的类型                    when (position % 3) {                        0 -> return BaseMultiQuickItem.FIRST_TYPE                        1 -> return BaseMultiQuickItem.SECOND_TYPE                        else -> {}                    }                    return 0                }            })            //2、绑定 item 类型,通过addItemType方法将类型和布局绑定。            getMultiTypeDelegate()                ?.addItemType(BaseMultiQuickItem.FIRST_TYPE, R.layout.layout_base_quick_first_item)                ?.addItemType(BaseMultiQuickItem.SECOND_TYPE, R.layout.layout_base_quick_second_item)        }    }

3.BaseProviderMultiAdapter

当有多种条目时,避免在convert方法中做大量的业务逻辑,把逻辑抽取到对应的ItemProvider中。有以下特点:
1、此适配器的数据类型可以是任意类型,只需在getItemType方法中返回类型
2、也不限定ViewHolder类型,可以在ItemProvider中自定义。
这个适配器看起来复杂,实际上就是将每种Item都抽离成为一个单独的类,然后整合到适配器中,最大化自定义ViewHolder类型,以减少适配器中的代码量。

编写适配如下,可以看到这里面的代码比较少,避免在convert方法中做大量的业务逻辑

class ProviderMultiAdapter : BaseProviderMultiAdapter<BaseMultiQuickItem?>() {                override fun getItemType(data: List<BaseMultiQuickItem?>, position: Int): Int {            when (position % 3) {                0 -> return BaseMultiQuickItem.FIRST_TYPE                1 -> return BaseMultiQuickItem.SECOND_TYPE                else -> {}            }            return 0        }        init {            // 注册 Provider            addItemProvider(FirstItemProvider())            addItemProvider(SecondItemProvider())        }    }

下面是FirstItemProvider的代码逻辑,SecondItemProvider是一样的。可以看到大量的业务逻辑,抽取到了对应的ItemProvider当中

class FirstItemProvider : BaseItemProvider<BaseMultiQuickItem?>() {    // 此item 类型    override val itemViewType: Int        get() = BaseMultiQuickItem.FIRST_TYPE    // 返回 item 布局 layout    override val layoutId: Int        get() = R.layout.layout_base_quick_first_item        override fun onCreateViewHolder(parent: ViewGroup, viewType:Int): BaseViewHolder {        return super.onCreateViewHolder(parent,viewType)    }    override fun convert(helper: BaseViewHolder, data: BaseMultiQuickItem?) {        // 设置 item 数据        if (helper.absoluteAdapterPosition % 2 === 0) {            helper.setText(R.id.formName, "第一行")        } else {            helper.setText(R.id.formName, "第二行")        }    }    // 点击 item 事件    override fun onClick(        helper: BaseViewHolder,        view: View,        data: BaseMultiQuickItem?,        position: Int    ) {        toast(context,"Click: $position")    }}

4.BaseSectionQuickAdapter

快速实现带头部的适配器,本质属于多布局,继承自BaseMultiItemQuickAdapter 使用此适配器时,需自定义类继承JSectionEntity抽象类,然后重新封装自己的数据类。
数据类编写如下:

class BaseSectionQuickItem(     override val isHeader: Boolean,      bean: BaseQuickerItem) : JSectionEntity()

适配器编写如下:

class SectionQuickAdapter(layoutResId: Int, sectionHeadResId: Int, data: MutableList<BaseSectionQuickItem>?) :        BaseSectionQuickAdapter<BaseSectionQuickItem, BaseViewHolder>(layoutResId, sectionHeadResId, data) {        override fun convert(helper: BaseViewHolder, item: BaseSectionQuickItem) {            helper.setText(R.id.editForm, "头部")        }        override fun convertHeader(helper: BaseViewHolder, item: BaseSectionQuickItem) {            helper.setText(R.id.editForm, "内容")        }    }

三、框架实现

封装万能的BaseViewHolder

//子布局中的控件    private SparseArray<View> mItemViews;    //子布局    private View mView;    //初始化ViewHolder    public BaseViewHolder(View itemView) {        super(itemView);        mView = itemView;        mItemViews = new SparseArray<>();    }        public View getView(@IdRes int viewId) {        View view = mItemViews.get(viewId);        if (view == null) {            view = mView.findViewById(viewId);            mItemViews.put(viewId, view);        }        return view;    }        public BaseViewHolder setText(@IdRes int viewId, @StringRes int resId) {        TextView textView = (TextView) getView(viewId);        textView.setText(resId);        return this;    }    public BaseViewHolder setOnClickListener(@IdRes int viewId, @NonNull View.OnClickListener            listener) {        View view = getView(viewId);        if (listener != null) {            view.setOnClickListener(listener);        }        return this;    }

主要实现:
1)使用SparseArray存储item布局中的控件,通过getView()去获取控件,如果在SparseArray中存在则直接获取,如果不存在则findViewById()然后再插入SparseArray中
2)设置一些操作方法:设置控件属性,添加点击事件等

SparseArray比HashMap更省内存,在某些条件下性能更好,主要是因为它避免了对key的自动装箱(int转为Integer类型),它内部则是通过两个数组来进行数据存储的,一个存储key,另外一个存储value,为了优化性能,它内部对数据还采取了压缩的方式来表示稀疏数组的数据,从而节约内存空间.

封装简单的BaseQuickAdapter

主要实现:
1)将重复的方法那些全部抽取到父类免得每次都重复写

onCreateViewHoldergetItemCountgetItemViewTypeonBindViewHoldergetItemgetItemPosition...
  1. 在onCreateViewHolder()里面写点击事件比较好,因为在onBindViewHolder()里面写的话,每次都要去绑定,会产生多余的消耗.
   val viewHolder = onCreateDefViewHolder(parent, viewType)       bindViewClickListener(viewHolder, viewType)
  1. 然后onBindViewHolder()方法是需要每个子类去实现的,我们可以提供一个convert()方法在里面,暴露给外面实现,用于绑定数据.
override fun onBindViewHolder(holder: VH, position: Int, payloads: MutableList<Any>) {        if (payloads.isEmpty()) {            onBindViewHolder(holder, position)            return        }        //Add up fetch logic, almost like load more, but simpler.        mUpFetchModule?.autoUpFetch(position)        //Do not move position, need to change before LoadMoreView binding        mLoadMoreModule?.autoLoadMore(position)        when (holder.itemViewType) {            LOAD_MORE_VIEW -> {                mLoadMoreModule?.let {                    it.loadMoreView.convert(holder, position, it.loadMoreStatus)                }            }            HEADER_VIEW, EMPTY_VIEW, FOOTER_VIEW -> return            else -> convert(holder, getItem(position - headerLayoutCount), payloads)        }    }
  1. 封装添加item,移除方法
open fun setList(list: Collection<T>?) //使用新的数据集合open fun setData(@IntRange(from = 0) index: Int, data: T) //改变某一位置数据open fun addData(@IntRange(from = 0) position: Int, data: T) //在指定位置添加一条新数据open fun addData(@IntRange(from = 0) position: Int, newData: Collection<T>) //在指定位置添加数据

移除类似
5) 封装item点击事件
包含条目和子控件的监听事件

fun setOnItemClickListener(listener: OnItemClickListener?) {        this.mOnItemClickListener = listener    }    ...........    fun getOnItemClickListener(): OnItemClickListener? = mOnItemClickListener    ...........

来源地址:https://blog.csdn.net/qq_40348833/article/details/125522050

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯