自定义View学习三(MRecyclerView)

前言:

RecyclerView在项目中的使用之频繁不用我再去过多的强调了。每一次我们使用RecyclerView的时候总要为RecyclerView写适配器,写 ViewHolder,并为Adapter转换数据等。如果我们需要为RecyclerView再添加Header,Footer,加载更多监听等,我们又不免要再写近百行代码。
可不可以不做这些?当然可以!下面请看MRecyclerView


MRecyclerView功能

已实现

  • 1、动态的添加Header,Footer;

  • 2、内置通用Adapter,不需要我们再写Adapter;

  • 3、内置通用ViewHolder,不需要再写ViewHolder;

  • 4、加载更多监听(支持GridLayoutManager和LinearLayoutManager,支持横向和纵向)

  • 5、Header,Item,Footer点击事件监听

将要添加的功能

  • 1、提供默认的Item进入动画

  • 2、丰富加载更多动画


MRecyclerView解析

内置通用Adapter和ViewHolder实现

MViewHolder
    //ViewHolder作用:复用已经加载过的item,减少绑定布局时间
    /**
     * 通用ViewHolder功能:将不同布局里面的view数量以及类型泛化,打造一个更为通用的ViewHolder
     */
inner class MViewHolder(val itemsView: View, val listener: MOnClickListener?) : RecyclerView.ViewHolder(itemsView) {
        private var views = SparseArray<View>()
        //通过在layout布局里的Id获取控件

        init {
            if (listener != null) {
                itemsView.setOnClickListener {
                    listener.onClick(itemsView)
                    //如果listener是ItemListener,由于我们对于ItemListener通常要多使用一项position,所以在此设定
                    if (listener is OnItemClickedListener) {
                        //如果有header,我们需要将位置减去一之后再返回
                        if (hasHeader) {
                            listener.onClick(adapterPosition - 1)
                        } else {
                            listener.onClick(adapterPosition)
                        }

                    }
                }
            }
        }

        fun getView(viewId: Int): View? {
            var view = views.get(viewId)
            if (view == null) {
                view = itemsView.findViewById(viewId)
                views.put(viewId, view)
            }
            return view
        }
    }
MRecyclerViewAdapter

    //数据显示适配器
    private inner class MRecyclerViewAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

        /**根据不同的ViewType,为MViewHolder传入不同的layout,从而构造不同类型的holder
         *现在没有对异常进行捕获
         *
         * 对于点击事件监听的设置:Header,Footer的点击事件监听在onCreateViewHolder里面设置
         * 但是NormalType的点击事件在onBindViewHolder里面设置,这样安排的主要原因是我们点击Item时,想要得到的回执数据主要是position
         */
        override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
            when (viewType) {
                HEADER -> {
                    return buildHolder(parent, headerRes, headerClickedListener)
                }
                FOOTER -> {
                    if (footerRes != NO_LAYOUT_VALUE)
                        return buildHolder(parent, footerRes, footerClickedListener)
                    else //如果存在Footer类型,但却没有Footer布局文件的话,那么我们使用这个holder的构造器
                        return buildHolder(getDefaultLoadMoreView(),footerClickedListener)
                }
            }
            return buildHolder(parent, itemRes, itemClickedListener)
        }




        override fun getItemCount(): Int {
            var ret = dataSize
            if (hasHeader) ret++
            //如果dataSize为0,且设置了加载更多监听,那么不显示footer
            if (dataSize != 0 || loadMoreListener != null){
                if (hasFooter) ret++
            }
            return ret
        }

        //数据绑定,按照resId为View设定数值,我们在此要向外提供设定数值方法,因为像ImageView的图片加载,
        // 我们往往是通过Glide等第三方图片加载框架
        override fun onBindViewHolder(holder: ViewHolder?, position: Int) {

            //如果没有提供bindServer,那么抛出异常
            if (bindDataServer == null) {
                throw NoBindDataServerException("You should provide a server binding data to viewHolder!")
            } else {
                holder as MViewHolder
                /**
                 * 当存在header的情况下,position包含了header,所以再根据position去取值得时候就会发生数组越界的问题
                 * 这个时候要将position的值减去1(对于header的position,它的值为-1,这一点我们需要注意)
                 */

                var positionModify = position
                if (hasHeader) positionModify = position - 1
                //这个应该需要修改,因为我们已经把数据提交到MRecyclerView内部了,这样写的话我们就使用不到我们提供的数据了。
                bindDataServer?.OnBindData(holder, positionModify, getItemViewType(position))
            }

        }

        //因为可能有Footer和Header,所以需要重写这个函数
        override fun getItemViewType(position: Int): Int {
            if (position == 0 && hasHeader) return HEADER
            
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值