我可以访问 TableLayout(10x10) 中的按钮而不必为每个按钮指定一个 ID 吗?
Can I access a button in a TableLayout(10x10) without having to give each button an id?
我创建了一个填充有按钮的 TableLayout。
我希望按钮在单击后改变颜色。但是将会有 100 个按钮,所以我不认为创建一个 id 和一个 onClickListener() 是为每个按钮处理它的正确方法。
有没有一种方法可以告诉我单击了哪个按钮,而无需将 ID 委托给每个按钮?
<TableRow
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/row1"
>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 1"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 2"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 3"
/>
</TableRow>
<TableRow
android:layout_height="0dp"
android:layout_weight="1"
>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 4"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 5"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 6"
/>
</TableRow>
<TableRow
android:layout_height="0dp"
android:layout_weight="1"
>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 7"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 8"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 9"
/>
</TableRow>
我已经看到了一些类似的问题,但是当我实施它们时似乎什么也没有发生。这是在我的 Main Activity 中,我尝试记录按钮点击但没有记录任何内容。
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)
}
})
您的 TableRow
包含一些 clickable = true
项目 (Buttons
),因此当您按下任何按钮时,它会吞下触摸事件并且不会将其传递给您所在的父级设置监听器。事实上,您当前的监听器永远不会触发,因为不可能 TableRow
点击 - 它完全由可点击的项目
实现
最好的方法是对所有按钮使用自定义 id
,但还有另一种方法 - 只需为这个 view/row[=17= 的所有子项设置相同的 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)
}
您有几种方法可以做到这一点 - 这取决于您想要做什么,但是您可以创建一个 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
) - 所以演员表按钮发生在那里。您还可以创建一个单击侦听器函数并在其中执行:
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 个点击侦听器函数的方法,只需重用同一个函数来处理所有函数!
我创建了一个填充有按钮的 TableLayout。
我希望按钮在单击后改变颜色。但是将会有 100 个按钮,所以我不认为创建一个 id 和一个 onClickListener() 是为每个按钮处理它的正确方法。
有没有一种方法可以告诉我单击了哪个按钮,而无需将 ID 委托给每个按钮?
<TableRow
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/row1"
>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 1"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 2"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 3"
/>
</TableRow>
<TableRow
android:layout_height="0dp"
android:layout_weight="1"
>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 4"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 5"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 6"
/>
</TableRow>
<TableRow
android:layout_height="0dp"
android:layout_weight="1"
>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 7"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 8"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button 9"
/>
</TableRow>
我已经看到了一些类似的问题,但是当我实施它们时似乎什么也没有发生。这是在我的 Main Activity 中,我尝试记录按钮点击但没有记录任何内容。
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)
}
})
您的 TableRow
包含一些 clickable = true
项目 (Buttons
),因此当您按下任何按钮时,它会吞下触摸事件并且不会将其传递给您所在的父级设置监听器。事实上,您当前的监听器永远不会触发,因为不可能 TableRow
点击 - 它完全由可点击的项目
最好的方法是对所有按钮使用自定义 id
,但还有另一种方法 - 只需为这个 view/row[=17= 的所有子项设置相同的 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)
}
您有几种方法可以做到这一点 - 这取决于您想要做什么,但是您可以创建一个 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
) - 所以演员表按钮发生在那里。您还可以创建一个单击侦听器函数并在其中执行:
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 个点击侦听器函数的方法,只需重用同一个函数来处理所有函数!