GridLayoutManager 實現 複雜列布局

迷失no發表於2019-03-26

GridLayoutManager 實現 複雜列布局

最近做直播頁面有個需求 直接上頁面

WechatIMG24.jpeg

豎直往下依次有四個ItemView 。 Item2 Item4數目依次不定 。 其中item2 資料和item4 相同 也就是整個頁面同一個介面 第一次我用 2個recyclerview LinearLayoutManager Vertical .顯示。

當然 大家知道 會存在item2 資料多而 item4 不能顯示的情況。 用scrollview 括起來 發現無用。果然還和listview 一樣。 解決辦法:

  • 在每個RecyclerView外層巢狀一個RelativeLayout,並設定descendantFocusability屬性。程式碼如下
<RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:descendantFocusability="blocksDescendants">
                <android.support.v7.widget.RecyclerView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:nestedScrollingEnabled="false">
                </android.support.v7.widget.RecyclerView>

            </RelativeLayout>
複製程式碼

果然資料正常顯示了 但是發現滑動卡頓。 本人都體驗差 肯定不行

  • 換瀑布流解決方案 StaggeredGridLayoutManager 假如 StaggeredGridLayoutManager 瀑布流 這樣的圖片水平顯示不就是我要的效果嗎。 然後經過嘗試發現不行 。它控制列的變化不太靈活。

回過頭再去google 查資料發現 gridlayoutmanager 可以很靈活的修改列數 。哎呀 這就對了 以前產生誤解 還是理解的不太透徹 一直以為gridlayoutmanager 就是 九宮格之類的職能 有時間一定要好好再研究原始碼。 果然效果立馬實現。

class LiveFollowAdapter(private val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {


    //todo  重構:1命名 2資料list 管理 3泛型 4 基類提取 5viewhold 分裝
    private var openRoomList: List<NAnchor> = ArrayList()
    private var closeRoomList: List<NAnchor> = ArrayList()
    private var dataList: MutableList<NAnchor> = mutableListOf()
    private val TAG = "LiveFollowAdapter"


    fun setDataList(data: NLiveFollow) {
        if (data?.closeRooms != null) {
//            openRoomList = data?.openRooms
            openRoomList = data?.closeRooms
        }
        if (data?.closeRooms != null) {
            closeRoomList = data?.closeRooms
        }

        dataList.clear()
        dataList.add(NAnchor("live_header"))
        dataList.addAll(openRoomList)
        dataList.add(NAnchor("unlive_header"))
        dataList.addAll(closeRoomList)
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            ViewType.ViewType1.ordinal -> ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_living_follow_header, parent, false))
            ViewType.ViewType2.ordinal -> ViewHolder2(LayoutInflater.from(context).inflate(R.layout.item_live_follow_grid, parent, false))
            ViewType.ViewType3.ordinal -> ViewHolder3(LayoutInflater.from(context).inflate(R.layout.item_unlive_follow_header, parent, false))
            ViewType.ViewType4.ordinal -> ViewHolder4(LayoutInflater.from(context).inflate(R.layout.item_live_follow_content, parent, false))
            else -> throw IllegalArgumentException(" holder error")
        }


    }

    override fun getItemViewType(position: Int): Int {
        if (position == 0) {
            return ViewType.ViewType1.ordinal
        } else if (position > 0 && openRoomList!!.size > 0 && position <= openRoomList.size) {
            return ViewType.ViewType2.ordinal
        } else if (position == openRoomList?.size + 1) {
            return ViewType.ViewType3.ordinal
        } else {
            return ViewType.ViewType4.ordinal
        }

    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (holder.itemViewType) {
            ViewType.ViewType1.ordinal -> {
                var viewHolder1 = holder as ViewHolder
                viewHolder1.bind(openRoomList.size)
            }
            ViewType.ViewType2.ordinal -> {
                var viewHolder2 = holder as ViewHolder2

                if (openRoomList.size > 0 && openRoomList.size == position && openRoomList.size % 2 != 0) {
                    viewHolder2.bind(dataList.get(position), true)
                } else {
                    viewHolder2.bind(dataList.get(position), false)
                }


            }
            ViewType.ViewType3.ordinal -> {
                var viewHolder3 = holder as ViewHolder3
                viewHolder3.bind(closeRoomList.size)
            }
            ViewType.ViewType4.ordinal -> {
                var viewHolder4 = holder as ViewHolder4
                viewHolder4.bind(dataList.get(position))
            }
        }
    }

    override fun getItemCount(): Int {
        return dataList.size
    }

    fun remove(position: Int) {
//        dataList.removeAt(position)
        notifyItemRemoved(position)
    }

    fun add(text: String, position: Int) {
//        dataList.add(position, text)
        notifyItemInserted(position)
    }
    
    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var num = itemView.findViewById<TextView>(R.id.tv_living_num)
        fun bind(size: Int) {
            num.text = "$size"
        }
    }

    class ViewHolder2(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var title = itemView.findViewById<TextView>(R.id.tv_live_anchor_title)
        var ivAvatar = itemView.findViewById<ImageView>(R.id.iv_avatar)
        var constraintLayout = itemView.findViewById<ConstraintLayout>(R.id.cl_layout)
        fun bind(anchor: NAnchor, flag: Boolean) {
            title.text = anchor?.user?.nickname
//            view.tv_anchor_motto.text = anchor.description

            GlideApp.with(itemView.context).load(anchor?.user?.avatar)
                    .placeholder(R.mipmap.iv_default_head)
                    .error(R.mipmap.iv_default_head)
                    .into(ivAvatar)
            //奇數時候 改動最後一個view
            if (flag) {
                var param: RecyclerView.LayoutParams = itemView.layoutParams as RecyclerView.LayoutParams
                val height = param.height
                val width = param.width
                param.width = height
                param.height = param.height
                itemView.visibility = View.VISIBLE
                itemView.setLayoutParams(param)
            }
        }
    }

    class ViewHolder3(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var num = itemView.findViewById<TextView>(R.id.tv_un_live_num)
        fun bind(size: Int) {
            num.text = "$size"
        }
    }

    class ViewHolder4(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var name = itemView.findViewById<TextView>(R.id.tv_un_live_name)
        var num = itemView.findViewById<TextView>(R.id.tv_un_live_follow_num)
        var civHead = itemView.findViewById<ImageView>(R.id.civ_head)
        //        var header = itemView.findViewById<ImageView>(R.id.civ_head)
        fun bind(anchor: NAnchor) {
            name.text = anchor.user.nickname
            num.text = anchor.likeCount.toString()
            GlideApp.with(itemView.context).load(anchor?.user?.avatar)
                    .placeholder(R.mipmap.iv_default_head)
                    .error(R.mipmap.iv_default_head)
                    .into(civHead)
        }
    }

    enum class ViewType {
        ViewType1, ViewType2, ViewType3, ViewType4
    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        val layoutManager = recyclerView.layoutManager
        if (layoutManager is GridLayoutManager) {
            layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                override fun getSpanSize(position: Int): Int {
                    //取多個item的每行佔用個數的最小公倍數,
                    //這裡最小公倍數為2  只有item2  顯示2行所以返回1  其餘為2
                    //他們對應的return 3,return 2,return 6
                    /*2122*/
                    var viewType = getItemViewType(position)
                    return when (viewType) {
                        ViewType.ViewType1.ordinal -> 2
                        ViewType.ViewType2.ordinal -> 1
                        ViewType.ViewType3.ordinal -> 2
                        else -> 2
                    }
                }
            }
        }
    }
}

複製程式碼

上面onAttachedToRecyclerView 方法 是在recyclerview 與 adapter 適配資料時候 呼叫的 這才是關鍵方法 再一次見識了 recyclerview 的無比強大! Fragment 中程式碼 就比較簡單了。

val layoutManager = GridLayoutManager(context, 2, GridLayoutManager.VERTICAL, false);
        rv_live_follow.layoutManager = layoutManager
        liveFollowAdapter = LiveFollowAdapter(context!!)
        rv_live_follow.addItemDecoration(GridSpacingItemDecoration(DensityUtil.dip2px(context!!, 9f)))
        rv_live_follow.adapter = liveFollowAdapter
複製程式碼

功能催的比較緊張 程式碼感覺還需要重構...

大功告成 搞定收工 又是一週結束了......

相關文章