Androidアプリで動的に追加された要素をIDを用いて特定し、更新する方法を紹介します。動的に生成されるボタンのクリックイベントで、同じく動的に追加された要素を更新する場合などに使用できます。
動的に追加したボタンで追加要素を更新するために
ちなみに本記事は以下記事の続編的な位置づけになっています。
Kotlinから動的にUIを追加する方法からじっくり知りたい方は以下記事を先にご覧ください。
以下本題です。
(当たり前のことですが)Androidアプリのボタン毎にクリックイベントを実装するためには以下が必要です。
- ボタン(UI)のID
- ボタン(UI)にクリックリスナを設定する
これは動的に追加したボタンでも同様です。
また編集対象となるUIも、特定のためにIDが必要です。
そこを踏まえて以下サンプルを作成しました。
動的に追加した要素を更新する機能を実装したサンプル
以下のようなサンプルを作成しました。
①上の「UIの追加」ボタンを押すと、②UI(ButtonとTextViewを含むLinearLayout)パーツが追加されます。
追加されたボタンを押すとTextView(黄)内の数字がカウントされていきます。
もちろんUIパーツはボタンを押すたびに追加され、追加された「それぞれのボタンとテキストビュー」は対応しています。
それぞれのテキストビューに表示される
XML
XMLは以下の通り。
上にボタン二つ、下は空のLinerLayout(id設定)です。
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_margin="20dp" android:gravity="center"> <!--UIを追加するボタン--> <Button android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="UIの追加" /> <Space android:layout_width="20dp" android:layout_height="wrap_content" /> <!--UIを削除するボタン--> <Button android:id="@+id/btnDel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="UIの削除" /> </LinearLayout> <!--レイアウト(動的にUIを追加される親UI)--> <LinearLayout android:id="@+id/ll1" android:layout_width="match_parent" android:layout_height="200dp" android:layout_margin="10dp" android:background="#eeeeee" />
Kotlin
Kotlinのコードは以下の通り。
「UIを追加」ボタンが押されたら呼ばれる関数addUI()と、追加されたボタン用のリスナクラス(NewButtonsClickListener)があります。
上記でも触れましたが、追加されるボタンとテキストビューにはIDを割り振る必要があります。
また動的に追加されたボタンを押した場合は、押されたボタンと対応するテキストビューを更新する必要があります。
つまりボタンとテキストビューのID同士を何かしらの手段で関連づける必要があります。
今回は、動的に追加されるボタンのIDを格納する配列と動的に追加されるテキストビューのIDを格納する配列を使用し、配列の何番目の要素か(インデックス番号)で関連付ける方法を採用しました。
- 動的に追加されるボタンのIDを格納する配列 :dynamicButtonIDs:Array<Int>
- 動的に追加されるテキストビューのIDを格納する配列:dynamicTextViewIDs:Array<Int>
UIへのID割り振りは、ViewCompat.generateViewId()を使用します
以下がKotlinのコードです。
何かしらのイベント(例えばボタンをクリック)するとaddUI()が呼ばれるよう実装してください。
// 動的に追加するUIパーツのID格納用配列 private var dynamicButtonIDs:Array<Int> = Array(0){0} private var dynamicTextViewIDs:Array<Int> = Array(0){0} // ボタンのリスナクラスの作成 private val listener = NewButtonsClickListener() // 動的にUIを追加する private fun addUI(){ // 追加するボタンを作成 var newBtn = Button(applicationContext) newBtn.id = ViewCompat.generateViewId() newBtn.text = "ボタン" + (dynamicButtonIDs.count()).toString() // ボタンにリスナ追加 newBtn.setOnClickListener(listener) // 中身のTextViewを生成 var newTextView = TextView(applicationContext) newTextView.id = ViewCompat.generateViewId() newTextView.text="0" newTextView.setBackgroundColor(Color.rgb(255,255,0)) newTextView.gravity = Gravity.CENTER // 動的に追加するLinearLayoutを生成(これにボタンとテキストビューを格納する) var newll = LinearLayout(applicationContext) newll.orientation=LinearLayout.VERTICAL // 上で生成したボタンとテキストをこのレイアウトに追加 newll.addView(newBtn) newll.addView(newTextView) //画面のUI(LinearLayout)に追加 binding.ll1.addView(newll) //それぞれのIDを「ID格納配列」に追加 dynamicButtonIDs += newBtn.id dynamicTextViewIDs += newTextView.id } // 追加ボタンのクリックリスナ private inner class NewButtonsClickListener:View.OnClickListener{ override fun onClick(v: View) { // 押されたボタンのIDを取得する val clickedBtnid:Int = v.id // 押されたボタンのIDに該当するインデックスをID配列から取得する val index = dynamicButtonIDs.indexOf(clickedBtnid) // ボタンと同じインデックスの、テキストビューをIDから特定 val trgtTextViewID = dynamicTextViewIDs[index] val tv = findViewById<TextView>(trgtTextViewID) // テキストビューのテキストを更新 tv.text = (tv.text.toString().toInt()+1).toString() } }
またリセットする場合は、以下処理を実施してください。
(例えばリセットボタンでの処理)
// 全てのUIを削除 binding.ll1.removeAllViews() // 全てのID配列を初期化 dynamicButtonIDs = Array(0){0} dynamicTextViewIDs = Array(0){0}
さいごに
動的に追加されたボタンと、それと対応するUI(今回はTextView)の紐付けを、ID管理用の配列を使用して実装しました。
他に方法があるかもしれませんが、この要素番号を使用する方法は汎用性もありそうなので一つの答えかなとは思っています。
以下関連記事など。
コメント