尝试以编程方式 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
作为按钮高度,以避免拉伸按钮高度。
我有一个 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
作为按钮高度,以避免拉伸按钮高度。