美文网首页AndroidUI
RecyclerView的使用(二):添加头部和尾部

RecyclerView的使用(二):添加头部和尾部

作者: 静水红阳 | 来源:发表于2021-02-18 18:46 被阅读0次

    前言

    Recyclerview作为Android的常用控件之一,相信大家对它应该是十分熟悉了,不熟悉的朋友可以参考我之前发的文章 RecyclerView的基本使用,其中包括有单item及多Item的基本使用。

    但是我们发现Recyclerview中没有提供方法直接添加headerViewfootView。对于我们自己去使用来说还需要从getItemViewType方法中进行重写,根据不同的类型添加不同的item布局,具体实现可以参考 RecyclerView的基本使用 中多item的使用。下面讨论下如何实现类似于ListViewaddHeaderView方法来添加列表的头部和尾部。

    设计与实现

    既然类比于ListView中的添加头部和尾部的方法,我们首先要先理清在listView中是如何去实现的,直接上源码:

        public void addHeaderView(View v, Object data, boolean isSelectable) {
            if (v.getParent() != null && v.getParent() != this) {
                if (Log.isLoggable(TAG, Log.WARN)) {
                    Log.w(TAG, "The specified child already has a parent. "
                               + "You must call removeView() on the child's parent first.");
                }
            }
            final FixedViewInfo info = new FixedViewInfo();
            info.view = v;
            info.data = data;
            info.isSelectable = isSelectable;
            mHeaderViewInfos.add(info);
            mAreAllItemsSelectable &= isSelectable;
    
            // Wrap the adapter if it wasn't already wrapped.
            if (mAdapter != null) {
                if (!(mAdapter instanceof HeaderViewListAdapter)) {
                    wrapHeaderListAdapterInternal();
                }
    
                // In the case of re-adding a header view, or adding one later on,
                // we need to notify the observer.
                if (mDataSetObserver != null) {
                    mDataSetObserver.onChanged();
                }
            }
        }
    

    从代码中可以看出,listView中对adapter进行了封装:HeaderViewListAdapter,使用此类用来处理对HeaderView的处理。
    查看此类代码,能够看出设计思想是通过使用了装饰模式的思路,对原有的adapter进行重新装饰,生成装饰类HeaderViewListAdapter用来处理head view。其重点工作包括如下几项:

    1. 重新计算count。
    2. 重新计算position对应的View的不同。

    了解了上述思路,接下来我们就可以动手去实现了,首先我们可以自定义一个继承自RecyclerView的控件,定义可以添加头部和尾部的方法,如下:

    class TestHeaderRecyclerView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : RecyclerView(context, attrs, defStyleAttr) {
        private var headerViews: ArrayList<View> = ArrayList()
        private var footerViews: ArrayList<View> = ArrayList()
        
        public fun addHeaderView(headerView: View) {
            headerViews.clear()
            headerViews.add(headerView)
        }
    
        public fun addFooterView(footerView: View) {
            footerViews.clear()
            footerViews.add(footerView)
        }
    
        public fun setAdapter(testAdapter: TestAdapter) {
            var adapter = TestHeaderAdapter(headerViews, footerViews, testAdapter)
            this.adapter = adapter
        }
    }
    

    然后实现一个adapter类去装饰原有的adapter,其实最终的实现方式也是通过设置adapter中不同的itemType去添加不同的布局View,示例代码如下:

    class TestHeaderAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>, IWrapperAdapter {
        private var mAdapter: TestAdapter? = null
        private var headerViews: ArrayList<View>? = ArrayList()
        private var footerViews: ArrayList<View>? = ArrayList()
        private var currentPosition: Int = 0
    
        constructor(
                headViews: ArrayList<View>,
                footViews: ArrayList<View>,
                adapter: TestAdapter
        ) {
            headerViews = headViews
            footerViews = footViews
            this.mAdapter = adapter
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            when (viewType) {
                TYPE_HEADER -> {
                    if (headerViews?.get(0) != null) {
                        return HeadViewHolder(headerViews!![0])
                    }
                }
                TYPE_FOOTER -> {
                    if (footerViews?.get(0) != null) {
                        return FootViewHolder(footerViews!![0])
                    }
                }
                TYPE_INVALID -> {
    
                }
                else -> {
                }
            }
            return mAdapter!!.onCreateViewHolder(parent, viewType)
        }
    
        override fun getItemCount(): Int {
            return if (mAdapter != null)
                mAdapter!!.itemCount + getFooterCount() + getHeaderCount()
            else
                getFooterCount() + getHeaderCount()
        }
    
        override fun getHeaderCount(): Int {
            return headerViews?.size ?: 0
        }
    
        override fun getFooterCount(): Int {
            return footerViews?.size ?: 0
        }
    
        override fun getItemViewType(position: Int): Int {
            currentPosition = position
            if (currentPosition < getHeaderCount())
                return TYPE_HEADER
            if (mAdapter != null) {
                if (currentPosition < itemCount - getFooterCount()) {
                    return mAdapter!!.getItemViewType(currentPosition - getHeaderCount())
                }
                return TYPE_FOOTER
            }
            return TYPE_INVALID
    
        }
    
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            var headCount = getHeaderCount()
            if (position < headCount) {
                return
            }
            var cPosition = position - headCount
            if (mAdapter != null) {
                var adapterCount = mAdapter!!.itemCount
                if (cPosition < adapterCount) {
                    mAdapter!!.onBindViewHolder(holder, cPosition)
                    return
                }
            }
        }
    
        class HeadViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        }
    
        class FootViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    
        }
    
        companion object {
            const val TYPE_HEADER = -1
            const val TYPE_FOOTER = -2
            const val TYPE_INVALID = -3
        }
    }
    

    这样最后调用的时候直接调用addHeaderViewaddFooterView即可添加View,如下:

        private fun setSimpleAdapter(listData: ArrayList<TestData>) {
            var headView1 = TestHeaderView(this)
            var footView1 = TestHeaderView(this)
            var testAdapter = TestAdapter(listData)
            listView?.addHeaderView(headView1)
            listView?.addFooterView(footView1)
            listView?.setAdapter(testAdapter)
            listView?.addItemDecoration(DividerItemDecoration(this,DividerItemDecoration.VERTICAL))
            listView?.layoutManager = LinearLayoutManager(this)
        }
    

    效果如下图:

    recyclerview添加头尾部.jpg

    总结

    类比于ListView的添加头尾部思路,为Recyclerview设计添加头尾部,本质上还是通过不同的itemtype实现不同的布局。

    相关文章

      网友评论

        本文标题:RecyclerView的使用(二):添加头部和尾部

        本文链接:https://www.haomeiwen.com/subject/ptykxltx.html