GridLayoutManager 實現 複雜列布局
最近做直播頁面有個需求 直接上頁面
豎直往下依次有四個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
複製程式碼
功能催的比較緊張 程式碼感覺還需要重構...
大功告成 搞定收工 又是一週結束了......