ブログでも書きましたがQiitaでも投稿します。
やりたいこと
○○という名前のcheckbox項目がチェックされたら、○○がmapコレクションで紐づいている数値を加算し、逆にチェックが外れたら減算する(≒合計値を元の値に戻す)。
準備
配列とマップ関数はこんな感じ。
//チェックボックスに表示する文字列の配列
val hoges = arrayOf("フガ", "ムニ", "モチャ", "ニャー")
//view名からIDを取得するためのマップ関数
val hogeMap = mapOf("フガ" to "huga", "ムニ" to "muni", "モチャ" to "mocha", "ニャー" to "nya-")
//チェックボックス項目に紐づいた値を設定するマップ関数
val hogePrices = mapOf("フガ" to 100, "ムニ" to 200, "モチャ" to 300, "ニャー" to 400)
あと、レイアウトファイルにはチェックボックスを項目数分用意し、IDを「checkBox + (hogeMapで設定した文字列)」となるようにネーミング。
例)ID : checkBoxhuga
コーディング
for文を使ってhogesの項目名をチェックボックスに設定し、クリックしたらチェックされているチェックボックス項目に紐づいた数値を加算します。
私が作っているアプリではスピナーの値とチェックボックスの合計を加算してTextviewに表示してます。
//チェックボックスの合計値を入れる変数を宣言
val checkPrice = 0
for (hoge in hoges){
//レイアウトファイルのチェックボックスのViewIDを取得
val viewId = resources.getIdentifier("checkBox"+ hogeMap[hoge], "id", packageName)
//findViewByIdでviewIDの紐付け
val checkbox = findViewById<CheckBox>(viewId)
//デフォルトをfalseに設定
checkbox.isChecked = false
//チェックボックスに表示する文字列をセット
checkbox.setText(hoge)
checkbox.setOnClickListener(View.OnClickListener{
//クリックするたび合計値は0にする
hogePrice = 0
//再度hogeの項目数分forを回す
for (hoge in hoges){
val viewId2 = resources.getIdentifier("checkBox"+ hogeMap[hoge], "id", packageName)
val checkbox2 = findViewById<CheckBox>(viewId2)
//チェックされている項目であれば、数値を合計値に加算する
if (checkbox2.isChecked == true){
checkPrice += hogePrices[hoge].toString().toInt() //map関数の戻り値はint?型なので、int? -> string -> intに変換が必要
}
}
//スピナーの値とチェック合計値を加算してsetText
val sum = spinnerPrice + checkPrice
price.setText(sum.toString())
最初は以下のような、全体の合計値を先に変数宣言してから、都度加算や減算するやり方でした。
checkboxだけの加算減算ならこれでも問題ないです。
if (checkbox2.isChecked()){
totalPrice += hogePrices[hoge].toString().toInt()
}else{
totalPrice -= hogePrices[hoge].toString().toInt()
}
ただ、これだと
スピナーの値をtotalPriceに代入(≠加算)
→チェックボックスを何個かON
→スピナー項目を変更(ここでtotalPriceがリセットしてスピナー項目の値そのものになる)
→チェックボックスをOFF
とすると、スピナー項目の値からチェックボックスの値分減算して想定より値を低く出せてしまうことが判明。
直前のスピナーで選択されていた項目を参照するやり方が見当たらないので、スピナーを変更したらチェックボックスを全部OFFにする対応策を考えたものの、ユーザーフレンドリーじゃないなと思い無事お蔵入りに。
ケースバイケースですが、こういう風に変更した部分だけ再計算するより、全体の値を再計算するとうまくいけるという学びがありました。