一、先看效果

二、实现原理

重写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