欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

RecyclerView跨行自适应调整

程序员文章站 2022-06-21 19:40:40
一、先看效果二、实现原理重写RecyclerView.LayoutManager,在onLayoutChildren时,重新测量计算布局,当多个item的宽度之和大于屏幕宽度时就换行,直接看以下代码,注释很详细:重写的LayoutManager:AutoFixLayoutManager.ktimport android.view.Viewimport android.view.ViewGroupimport androidx.core.view.getimport androi...

一、先看效果

RecyclerView跨行自适应调整

二、实现原理

重写RecyclerView.LayoutManager,在onLayoutChildren时,重新测量计算布局,当多个item的宽度之和大于屏幕宽度时就换行,直接看以下代码,注释很详细:

重写的LayoutManager  AutoFixLayoutManager.kt
import android.view.View
import android.view.ViewGroup
import androidx.core.view.get
import androidx.recyclerview.widget.RecyclerView


class AutoFixLayoutManager : RecyclerView.LayoutManager() {
    private var parentScale = 1f
    private var childScale = 1f
    override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
        return RecyclerView.LayoutParams(
            RecyclerView.LayoutParams.WRAP_CONTENT,
            RecyclerView.LayoutParams.WRAP_CONTENT
        )
    }

    override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State?) {
        detachAndScrapAttachedViews(recycler)
        //屏幕总宽度
        val sumWidth = width
        var curLineWidth = 0
        var curLineTop = 0
        var lastLineMaxHeight = 0
        for (i in 0 until itemCount) {
            //循环获取item的宽高
            val view: View = recycler.getViewForPosition(i)
            measureChildWithMargins(view, 0, 0)
            val width = getDecoratedMeasuredWidth(view)
            val height = getDecoratedMeasuredHeight(view)
            if (parentScale != 1f && state?.isMeasuring == true) {
                //缩放ViewGroup
                val params: ViewGroup.LayoutParams = view.layoutParams
                params.width = (width * parentScale).toInt()
                params.height = (height * parentScale).toInt()
                view.layoutParams = params
            }
            addView(view)
            if (childScale != 1f && state?.isMeasuring == true) {
                //缩放childView
                scaleItemChildView(view as ViewGroup)
            }
            curLineWidth += width
            if (curLineWidth <= sumWidth) {
                //不需要换行
                layoutDecorated(
                    view,
                    curLineWidth - width,
                    curLineTop,
                    curLineWidth,
                    curLineTop + height
                )
                //比较当前行多有item的最大高度
                lastLineMaxHeight = Math.max(lastLineMaxHeight, height)
            } else {
                //换行
                curLineWidth = width
                if (lastLineMaxHeight == 0) {
                    lastLineMaxHeight = height
                }
                //记录当前行top
                curLineTop += lastLineMaxHeight
                layoutDecorated(view, 0, curLineTop, width, curLineTop + height)
                lastLineMaxHeight = height
            }
        }
    }

    /**
     * 缩放item内子布局
     */
    private fun scaleItemChildView(viewGroup: ViewGroup) {
        for (index in 0 until viewGroup.childCount) {
            val view = viewGroup[index]
            val width = view.layoutParams.width
            val height = view.layoutParams.height
            if (width < 0 || height < 0) {
                continue
            }
            val params: ViewGroup.LayoutParams = view.layoutParams
            params.width = (width * childScale).toInt()
            params.height = (height * childScale).toInt()
            view.layoutParams = params
            //设置childView在parentView内居中
            val left = viewGroup.layoutParams.width / 2 - view.layoutParams.width / 2
            val top = viewGroup.layoutParams.height / 2 - view.layoutParams.height / 2
            val right = left + view.layoutParams.width
            val bottom = top + view.layoutParams.height
            view.layout(left, top, right, bottom)
        }
    }

    /**
     * 设置item进行缩放
     */
    fun setScale(parentScale: Float, childScale: Float) {
        this.parentScale = parentScale
        this.childScale = childScale
    }
}

adapter:AutoFixListAdapter 

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView


class AutoFixListAdapter constructor(list: ArrayList<String>, context: Context) :
    RecyclerView.Adapter<AutoFixListAdapter.AutoFixViewHolder>() {

    private var context = context
    private var list = list
    private var isShowAll = true

    class AutoFixViewHolder internal constructor(view: View) : RecyclerView.ViewHolder(view) {
        var tvName: TextView = view.findViewById(R.id.name)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AutoFixViewHolder {
        return AutoFixViewHolder(
            LayoutInflater.from(context).inflate(R.layout.app_item, parent, false)
        )
    }

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

    override fun onBindViewHolder(holder: AutoFixViewHolder, position: Int) {
        if (holder != null) {
            //不重用item,我的测量方式是以不重用item为前提设计的,如果重用要重新设计测量方式
            holder.setIsRecyclable(false)
            holder.tvName.text = list[position]
            if (isShowAll) {
                holder.tvName.visibility = View.VISIBLE
            } else {
                holder.tvName.visibility = View.GONE
            }
        }
    }

    fun changeShowType() {
        isShowAll = !isShowAll
        notifyDataSetChanged()
    }

    fun isShowAll(): Boolean {
        return isShowAll
    }
}

MainAcitivy

import android.os.Bundle
import android.widget.ImageButton
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {
    private lateinit var recyclerView: RecyclerView
    private lateinit var imageButton: ImageButton
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initView()
    }

    private fun initView() {
        imageButton = findViewById(R.id.imageButton)
        recyclerView = findViewById(R.id.recycler)
        var manager = AutoFixLayoutManager()
        manager.isAutoMeasureEnabled = true
        recyclerView.layoutManager = manager
        var adapter = AutoFixListAdapter(initData(), this)
        recyclerView.adapter = adapter
        imageButton.setOnClickListener {
            adapter.changeShowType()
            if (adapter.isShowAll()) {
                imageButton.setBackgroundResource(R.mipmap.down)
                manager.setScale(1f, 1f)
            } else {
                imageButton.setBackgroundResource(R.mipmap.right)
                manager.setScale(0.6f, 0.5f)
            }
        }
    }

    private fun initData(): ArrayList<String> {
        var list = ArrayList<String>()
        for (index in 1..14) {
            list.add("应用" + index)
        }
        return list
    }
}

app_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="4dp">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="4dp"
        android:src="@mipmap/ic_launcher_round" />

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:text="范德萨发" />
</LinearLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageButton
        android:id="@+id/imageButton"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_margin="16dp"
        android:background="@mipmap/down" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageButton" />
</LinearLayout>

 

本文地址:https://blog.csdn.net/qq_24125575/article/details/110144592