美文网首页
RecyclerView之Header和Footer的添加

RecyclerView之Header和Footer的添加

作者: 小和尚恋红尘 | 来源:发表于2017-06-27 15:42 被阅读0次

    一,添加Header和Footer

    在Adapter中新添加一些int值,用于区分添加Header,Footer,还是都没有添加

            val TYPE_FOOTER = 1//添加Footer
            val TYPE_HEADER = 2//添加Header
            val TYPE_NORMAL = 0//两者都没有添加
    

    在Adapter中新暴漏两个方法,用于设置Header和Footer

        fun setHeaderView(hv: View){
            headerView = hv
            notifyItemInserted(0)
        }
    
        fun setFooterView(fv: View){
            footerView = fv
            notifyItemInserted(itemCount - 1)
        }
    

    根据是否添加了Header和Footer来设置itemCount的值

        override fun getItemCount(): Int{
            if (headerView != null && footerView != null)
                return items.size + 2
            else if(headerView == null && footerView == null)
                return items.size
            else
                return items.size + 1
        }
    

    复写getItemViewType方法,用于区分是否需要添加Header和Footer

        override fun getItemViewType(position: Int): Int {
            if (headerView == null && footerView == null)
                return TYPE_NORMAL
            if(position == 0)
                return TYPE_HEADER
            if(position == itemCount-1)
                return TYPE_FOOTER
            return TYPE_NORMAL
        }
    

    onCreateViewHolder中根据设置的标记来分别绑定布局文件

        override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
            if (headerView != null && viewType == TYPE_HEADER)
                return ViewHolder(headerView!!)
            if (footerView != null && viewType == TYPE_FOOTER)
                return ViewHolder(footerView!!)
    
            val view = LayoutInflater.from(context).inflate(R.layout.item_rc_4st, parent, false)
            view.setOnClickListener { view ->  listener?.onItemClick(view, view.tag as Int) }
            return ViewHolder(view)
        }
    

    或者写成

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
            if (headerView != null && viewType == TYPE_HEADER) {
                val view = LayoutInflater.from(context).inflate(R.layout.header, parent, false)
                return ViewHolder(view)      
            }
            if (footerView != null && viewType == TYPE_FOOTER) {
                val view = LayoutInflater.from(context).inflate(R.layout.footer, parent, false)
                return ViewHolder(view)
            }
            val view = LayoutInflater.from(context).inflate(R.layout.item_rc_4st, parent, false)
            view.setOnClickListener { view ->  listener?.onItemClick(view, view.tag as Int) }
            return ViewHolder(view)
        }
    

    onBindViewHolder增加多Footer和Header的处理。如果添加了Header的话,那么Header的位置为‘0’,此时pos位置的值为数据中pos-1位置的值

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            if (getItemViewType(position) == TYPE_HEADER) return
            else if (getItemViewType(position) == TYPE_FOOTER) return
            else{
                if (holder is RecyclerViewAddHeaderAndFooterAdapter.ViewHolder){
                    Log.e("hjd", "position->"+ position)
                    val positionTemp = if (headerView == null) position else position -1//计算pos位置
                    if (positionTemp < items.size){
                        holder.tv!!.text = items[positionTemp]
                        holder.itemView.tag= positionTemp
                    }
                }
            }
        }
    

    这样添加HeaderFooter就完成了,下面来看Adapter中的完整代码

    class RecyclerViewAddHeaderAndFooterAdapter(var context: Context, var items: ArrayList<String>):RecyclerView.Adapter<RecyclerViewAddHeaderAndFooterAdapter.ViewHolder>(){
        companion object{
            val TYPE_FOOTER = 1//添加Footer
            val TYPE_HEADER = 2//添加Header
            val TYPE_NORMAL = 0//两者都没有添加
            var headerView: View? = null
            var footerView: View? = null
        }
        var list = ArrayList<String>()
        init {
            list = items
        }
    
        fun setHeaderView(hv: View){
            headerView = hv
            notifyItemInserted(0)
        }
    
        fun setFooterView(fv: View){
            footerView = fv
            notifyItemInserted(itemCount - 1)
        }
    
        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            if (getItemViewType(position) == TYPE_HEADER) return
            else if (getItemViewType(position) == TYPE_FOOTER) return
            else{
                if (holder is RecyclerViewAddHeaderAndFooterAdapter.ViewHolder){
                    Log.e("hjd", "position->"+ position)
                    val positionTemp = if (headerView == null) position else position -1
                    if (positionTemp < items.size){
                        holder.tv!!.text = items[positionTemp]
                        holder.itemView.tag= positionTemp
                    }
                }
            }
        }
    
        override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
            if (headerView != null && viewType == TYPE_HEADER)
                return ViewHolder(headerView!!)
            if (footerView != null && viewType == TYPE_FOOTER)
                return ViewHolder(footerView!!)
    
            val view = LayoutInflater.from(context).inflate(R.layout.item_rc_4st, parent, false)
            view.setOnClickListener { view ->  listener?.onItemClick(view, view.tag as Int) }
            return ViewHolder(view)
        }
    
        override fun getItemCount(): Int{
            if (headerView != null && footerView != null)
                return items.size + 2
            else if(headerView == null && footerView == null)
                return items.size
            else
                return items.size + 1
        }
    
        override fun getItemViewType(position: Int): Int {
            if (headerView == null && footerView == null)
                return TYPE_NORMAL
            if(position == 0)
                return TYPE_HEADER
            if(position == itemCount-1)
                return TYPE_FOOTER
            return TYPE_NORMAL
        }
    
        class ViewHolder(itemTv: View):RecyclerView.ViewHolder(itemTv){
            var tv: TextView? = null
    
            init {
                if (headerView != itemTv && footerView != itemTv) {
                    tv = itemTv.findViewById(R.id.tv) as TextView
                }
            }
    
        }
    
    
        private var listener: OnItemClickListener?=null
    
        fun setOnItemClickListener(l: OnItemClickListener): Unit{
            this.listener = l
        }
        interface OnItemClickListener{
            fun onItemClick(view: View, pos: Int)
        }
    
        fun addItem(pos: Int){
            list.add(pos, "Add item"+ pos)
            notifyItemInserted(pos)
        }
    
        fun delItem(pos: Int){
            list.removeAt(pos)
            notifyItemRemoved(pos)
        }
    }
    

    因为我没有在上面的Adapter中直接设置HeaderFooter的布局,因此需要在Activity中进行设置

        /**
         * 添加HeaderView
         */
        fun setHeaderView(rv: RecyclerView, adapter: RecyclerViewAddHeaderAndFooterAdapter){
            val hv = LayoutInflater.from(this).inflate(R.layout.header, rv, false)
            adapter.setHeaderView(hv)
        }
    
        /**
         * 添加FooterView
         */
        fun setFooterView(rv: RecyclerView, adapter: RecyclerViewAddHeaderAndFooterAdapter){
            val hv = LayoutInflater.from(this).inflate(R.layout.footer, rv, false)
            adapter.setFooterView(hv)
        }
    

    效果图如下


    device-2017-06-27-094800.png

    上面效果使用的显示方式为LinearLayoutManager,现在换成GridLayoutManager,运行,效果图为:

    device-2017-06-27-101049.png
    可以看出,HeaderFooter都只是占据了一个Item的位置,而我们希望的是占据一行,所以这样明显不符合我们的要求。在GridLayoutManager中提供了setSpanSizeLookup方法,它就是用来设置列数的,我们可以通过调用此方法来满足我们的要求。
    在Adapter中,复写onAttachedToRecyclerView方法
    //此为Kotlin代码
    override fun onAttachedToRecyclerView(recyclerView: RecyclerView?) {
            val manager = recyclerView!!.layoutManager
            if (manager == null){
                Log.e("hjd", "layoutManager == null")
            }else {
                if (manager is GridLayoutManager) {
                    val glm: GridLayoutManager = manager
                    glm.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                        override fun getSpanSize(position: Int): Int {
                            if (getItemViewType(position) == TYPE_HEADER || getItemViewType(position) == TYPE_FOOTER)
                                return glm.spanCount
                            else
                                return 1
                        }
                    }
                }
            }
        }
    
    //此为Java代码
    @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (layoutManager == null){
                Log.e("hjd", "layoutManager == null");
            }else {
                if (layoutManager instanceof GridLayoutManager){
                    final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
                    gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                        @Override
                        public int getSpanSize(int position) {
                            if (getItemViewType(position) == TYPE_FOOTER || getItemViewType(position) == TYPE_HEADER)
                                return gridLayoutManager.getSpanCount();
                            else
                                return 1;
                        }
                    });
                }
            }
        }
    

    运行程序,发现上面的Kotlin代码并没有实现,我们的效果。而
    Java代码能够正确实现我们的效果,图为:

    device-2017-06-27-143323.png

    当然也并不是只能在Adapter中进行设置,也可以直接在Activity中进行:

    //此为Kotlin代码
    gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup(){
                override fun getSpanSize(position: Int): Int {
                    if (mAdapter!!.getItemViewType(position) == 1 || mAdapter!!.getItemViewType(position) == 2){
                        return gridLayoutManager.spanCount
                    }else
                        return 1
                }
            }
    
    
    

    上面两种代码都可以实现上图效果。
    现在换成StaggeredGridLayoutManager,运行,效果图为:

    device-2017-06-27-101049.png
    也只是占用一个Item的位置,因此我们也要进行配置,以满足我们的要求
    //此为Kotlin代码
        override fun onViewAttachedToWindow(holder: ViewHolder?) {
            super.onViewAttachedToWindow(holder)
            val layoutParams = holder!!.itemView.layoutParams
            if (layoutParams != null && layoutParams is StaggeredGridLayoutManager.LayoutParams) {
                layoutParams.isFullSpan = getItemViewType(holder.layoutPosition) == TYPE_HEADER || getItemViewType(holder.layoutPosition) == TYPE_FOOTER
            }
        }
    
    //此为Java代码
    @Override
        public void onViewAttachedToWindow(ViewHodler holder) {
            super.onViewAttachedToWindow(holder);
            ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
            if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams){
                StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) layoutParams;
                lp.setFullSpan(getItemViewType(holder.getLayoutPosition())== TYPE_HEADER || getItemViewType(holder.getLayoutPosition()) == TYPE_FOOTER);
            }
        }
    

    运行程序,效果图为:


    device-2017-06-27-152155.png

    这样RecyclerView中三种显示方式,都能正确显示HeaderFooter
    好了,RecyclerView添加HeaderFooter就介绍到这里,不足之处请各位指正,谢谢。下一篇讲解RecyclerView之上拉加载下拉刷新

    参考文章

    相关文章

      网友评论

          本文标题:RecyclerView之Header和Footer的添加

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