美文网首页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