【问题标题】:Can I access a button in a TableLayout(10x10) without having to give each button an id?我可以访问 TableLayout(10x10) 中的按钮而不必给每个按钮一个 id 吗?
【发布时间】:2021-12-23 21:16:24
【问题描述】:

我创建了一个用按钮填充的 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>

我见过一些类似的问题,但是当我实施它们时,似乎什么也没发生。这是在我的主要活动中,我尝试记录按钮单击但没有记录任何内容。

  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)
        }

    })

【问题讨论】:

    标签: android kotlin android-layout


    【解决方案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 - 它完全由可点击的项目完成

      最好的方法是对所有按钮使用自定义 ids,但还有另一种方法 - 只需为此视图/行的所有子项设置相同的 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)
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-28
        • 2021-12-16
        • 2014-10-13
        • 2019-01-01
        • 1970-01-01
        相关资源
        最近更新 更多