尝试以编程方式 space 网格布局均匀

Trying programmaticly to space a grid layout evenly

我有一个 GridLayout,它应该显示 25 个均匀分布的按钮。为了能够设置一个 onClickListener 而无需调用每个它们,我想以编程方式进行。 我用网格本身制作了一个布局资源文件来绑定它并能够膨胀它

activity.xml
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:grid="http://schemas.android.com/apk/res-auto"
    android:id="@+id/bingo_grid"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerHorizontal="true"
    android:columnCount="5"
    android:rowCount="5"
    tools:context=".BingoActivity" />

现在我正在创建字段:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val bingoField = (1).rangeTo(25).toSet().toIntArray()
        binding = BingoActivityBinding.inflate(layoutInflater)

        setContentView(binding.root)
        binding.bingoGrid.alignmentMode = GridLayout.ALIGN_BOUNDS

        val bingoFieldGrid = binding.bingoGrid
        bingoFieldGrid.alignmentMode = GridLayout.ALIGN_BOUNDS
        bingoField.forEach {
            val button = createButton(it.toString())
            val gridLayoutParams = GridLayout.LayoutParams().apply {
                rowSpec = spec(GridLayout.UNDEFINED, GridLayout.CENTER, 1f)
                columnSpec = spec(GridLayout.UNDEFINED, GridLayout.CENTER, 1f)
                height = GridLayout.LayoutParams.WRAP_CONTENT
                width = GridLayout.LayoutParams.WRAP_CONTENT
            }

            bingoFieldGrid.addView(button, gridLayoutParams)
        }
    @RequiresApi(Build.VERSION_CODES.M)
    private fun createButton(buttonText: String): Button {
        var isCompleted = false
        return Button(baseContext).apply {
            setBackgroundColor(getColor(R.color.red))
            gravity = Gravity.CENTER
            text = buttonText
            setOnClickListener {
                isCompleted = if (!isCompleted) {
                    setBackgroundColor(getColor(R.color.green))
                    true
                } else {
                    setBackgroundColor(getColor(R.color.red))
                    false
                }
            }
        }
    }

因此,字段自动生成没有问题,但间距不正确:

我对旧布局还很陌生,有没有办法轻松实现?

您正在创建两种不同类型的 LayoutParams,这没有意义。根本不应该涉及 LinearLayout。

它们的工作方式是每个 child 都应该获得一组与其 parent ViewGroup 使用的 LayoutParams 类型相匹配的 LayoutParams。所以在这种情况下 parent 是 GridLayout,所以每个 child 应该使用 GridLayout.LayoutParams.

的实例添加

GridLayout.LayoutParams 的工作方式是定义一行 Spec 和一列 Spec 来描述 child 应该如何占用单元格。我们希望它们采用单个下一个单元格,因此我们可以将第一个参数保留为未定义。我们需要给他们一个比 0 多的 weight,这样他们就能平均分享剩余的 space。我使用 1f 作为权重。

我对按钮使用大小为 0 的 FILL,以便它们填充单元格。边距使它们之间有一些差距。

我将高度和宽度设置为 0 以防止它们过大。如果行或列变得太大而不适合屏幕,则布局会太大。

您可能想要使用 MaterialButton 而不是普通的 Button,这样您就可以轻松地为背景颜色着色,而无需简单地将其设为静态纯色矩形。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    binding = BingoBinding.inflate(layoutInflater)
    setContentView(binding.root)

    binding.bingoGrid.alignmentMode = GridLayout.ALIGN_BOUNDS

    for (num in 1..25) {
        val button = MaterialButton(this).apply {
            setBackgroundColor(resources.getColor(R.color.blue_500))
            gravity = Gravity.CENTER
            text = num.toString()
            setPadding(0)
        }
        val params = GridLayout.LayoutParams().apply {
            rowSpec = spec(GridLayout.UNDEFINED, GridLayout.FILL, 1f)
            columnSpec = spec(GridLayout.UNDEFINED, GridLayout.FILL, 1f)
            width = 0
            height = 0
            setMargins((4 * resources.displayMetrics.density).toInt())
        }
        binding.bingoGrid.addView(button, params)
    }

}

AndroidStudio 对导入 spec 函数很挑剔。我不得不在顶部手动添加:

import android.widget.GridLayout.Spec.*

你可以考虑Google ConstraintLayout Flows:

设置元素数量使用app:flow_maxElementsWrap="5"

布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.constraintlayout.helper.widget.Flow
        android:id="@+id/flow"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:flow_horizontalGap="8dp"
        app:flow_maxElementsWrap="5"
        app:flow_verticalGap="8dp"
        app:flow_verticalStyle="packed"
        app:flow_wrapMode="chain" />

</androidx.constraintlayout.widget.ConstraintLayout>

然后以编程方式将按钮添加到 ConstraintLayout:

val root = findViewById<ViewGroup>(R.id.root)
val size = 25
val array = IntArray(size)
for (i in 0 until size) {
    array[i] = i + 1
    val button = Button(this).apply {
        layoutParams = ViewGroup.LayoutParams(0, 0)
        id = i + 1
        text = (i + 1).toString()
    }
    root.addView(button)
}
val flow = findViewById<Flow>(R.id.flow)
flow.referencedIds = array

提示:您可以使用 WRAP_CONTENT 作为按钮高度,以避免拉伸按钮高度。