我可以访问 TableLayout(10x10) 中的按钮而不必给每个按钮一个 id 吗?
Posted
技术标签:
【中文标题】我可以访问 TableLayout(10x10) 中的按钮而不必给每个按钮一个 id 吗?【英文标题】:Can I access a button in a TableLayout(10x10) without having to give each button an id? 【发布时间】:2021-12-23 21:16:24 【问题描述】:我创建了一个用按钮填充的 TableLayout。
我希望按钮在单击后改变颜色。但是会有 100 个按钮,所以我不认为为每个按钮创建一个 id 和一个 onClickListener() 是正确的方法。
有没有一种方法可以告诉我点击了哪个按钮,而无需将 id 委派给每个按钮?
<TableRow
android:layout_
android:layout_weight="1"
android:id="@+id/row1"
>
<Button
android:layout_
android:layout_
android:layout_weight="1"
android:text="Button 1"
/>
<Button
android:layout_
android:layout_
android:layout_weight="1"
android:text="Button 2"
/>
<Button
android:layout_
android:layout_
android:layout_weight="1"
android:text="Button 3"
/>
</TableRow>
<TableRow
android:layout_
android:layout_weight="1"
>
<Button
android:layout_
android:layout_
android:layout_weight="1"
android:text="Button 4"
/>
<Button
android:layout_
android:layout_
android:layout_weight="1"
android:text="Button 5"
/>
<Button
android:layout_
android:layout_
android:layout_weight="1"
android:text="Button 6"
/>
</TableRow>
<TableRow
android:layout_
android:layout_weight="1"
>
<Button
android:layout_
android:layout_
android:layout_weight="1"
android:text="Button 7"
/>
<Button
android:layout_
android:layout_
android:layout_weight="1"
android:text="Button 8"
/>
<Button
android:layout_
android:layout_
android:layout_weight="1"
android:text="Button 9"
/>
</TableRow>
我见过一些类似的问题,但是当我实施它们时,似乎什么也没发生。这是在我的主要活动中,我尝试记录按钮单击但没有记录任何内容。
val table : TableLayout = findViewById(R.id.table1)
val row : TableRow = findViewById(R.id.row1)
row.setOnClickListener(object : View.OnClickListener
override fun onClick(p0: View?)
val tr = p0?.getParent() as TableRow
val rowIndex: Int = table.indexOfChild(p0)
Log.i("TAG!!!!!!!!!!!!!!!", "onClick: " + tr)
)
【问题讨论】:
【参考方案1】:您有几种方法 - 这取决于您想要做什么,但您可以创建一个 View
查找(因此可以将每个按钮与一些数据相关联),或者您可以以编程方式将一些数据分配给按钮本身(比如setTag(Object)
)。
这是一个简单的“给每个按钮一个索引”的方法:
lateinit var buttons: List<Button>
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
super.onViewCreated(view, savedInstanceState)
// basically get each table row, and turn them into a stream of buttons.
// flatMap means that instead of mapping each row to a List<Button>,
// so we get a list of lists, they're unpacked into a single list of all the contents
buttons = view.findViewById<TableLayout>(R.id.table1)
.children.filterIsInstance<TableRow>()
.flatMap row -> row.children.filterIsInstance<Button>()
.onEach it.setOnClickListener(::onButtonClick) // set this here why not
.toList()
private fun onButtonClick(view: View)
val button = view as Button
Toast.makeText(requireContext(), "Button $buttons.indexOf(button) + 1 clicked!", Toast.LENGTH_SHORT).show()
以下是嵌套迭代的方法,以便跟踪按钮所在的行和列,并且可以使用其tag
在按钮本身上设置该信息:
data class TableButton(val row: Int, val column: Int)
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
super.onViewCreated(view, savedInstanceState)
// could be neater but you get the idea!
view.findViewById<TableLayout>(R.id.table1)
.children.filterIsInstance<TableRow>()
.mapIndexed rowNum, row ->
row.children.filterIsInstance<Button>()
.forEachIndexed colNum, button ->
button.tag = TableButton(rowNum, colNum)
button.setOnClickListener(::onButtonClick)
private fun onButtonClick(view: View)
val position = view.tag as TableButton
Toast.makeText(requireContext(), "Row $position.row, column: $position.column", Toast.LENGTH_SHORT).show()
我使onButtonClick
函数与单击侦听器签名匹配(采用View
参数),因此您可以将其作为函数引用(::onButtonClick
)传递 - 因此对 Button 的强制转换发生在其中。您还可以创建一个单击侦听器函数并在其中执行它:
val clickListener = v: View -> onButtonClick(v as Button)
buttons.forEach it.setOnClickListener(clickListener)
private fun onButtonClick(button: Button)
Toast.makeText(requireContext(), "Button $buttons.indexOf(button) + 1 clicked!", Toast.LENGTH_SHORT).show()
这让onButtonClick
有点“干净”,因为它现在只需要按钮。或者您可以完全删除单独的函数并在 lambda 函数中完成所有操作 - 这些只是避免创建 100 个单击侦听器函数的方法,而只需重用同一个函数来处理它!
【讨论】:
【参考方案2】:您的TableRow
包含一些clickable = true
项目(Buttons
),因此当您按下任何按钮时,它会吞下触摸事件并且不会将其传递给您设置监听器的父级。实际上,您当前的听众永远不会触发,因为不可能点击 TableRow
- 它完全由可点击的项目完成
最好的方法是对所有按钮使用自定义 id
s,但还有另一种方法 - 只需为此视图/行的所有子项设置相同的 OnClickListener
val onClick = object : View.OnClickListener
override fun onClick(p0: View?) // p0 will be a button
val tr = p0?.getParent() as TableRow // child of TableRow for shure
val rowIndex = tr.indexOfChild(p0) // index of clicked child in its parent (row)
val tableIndex = table.indexOfChild(tr) // index of this row in whole table
Log.i("TAG!!!!!!!!!!!!!!!",
"onClick rowIndex:" + rowIndex + " tableIndex:" + tableIndex)
val row : TableRow = findViewById(R.id.row1)
for (i until 0..row.childCount)
row.getChildAt(i).setOnClickListener(onClick)
【讨论】:
以上是关于我可以访问 TableLayout(10x10) 中的按钮而不必给每个按钮一个 id 吗?的主要内容,如果未能解决你的问题,请参考以下文章