mune diary

Hello, World!

ConstraintHelper で ConstraintLayout な RadioGroup を実装する

ConstraintHelper とは

指定した複数の View に対して同様な処理をさせることができます。ConstraintHelper を拡張したクラスとして Barrier, Flow, Group などがすでにあります。
今回は既存の拡張クラスにならって独自の拡張クラスを作成しようと思います。

素の RadioGroup 内では ConstraintLayout を使用できない

RadioGroup は LinearLayout を継承しているため、ConstraintLayout では RadioButton のスコープを設定することができません。なので、ConstraintLayout を継承した独自 RadioGroup クラスを作成する方法がありますが、正直面倒くさいです。
Y.A.M の 雑記帳: Android TableLayout, RelativeLayout で RadioButton を使う

今回は複数の RadioButton を同一のスコープに設定する、つまり OnCheckedChangeListener を共通化したいだけですので、上記の方法だとちょっと重い気がします。

そこで ConstraintHelper の出番です。リスナーを共通化する処理を拡張クラスとして書けば ConstraintLayout で RadioButton を同一のスコープ(リスナー)で扱うことができます。

コード

import android.content.Context
import android.util.AttributeSet
import android.widget.CompoundButton
import androidx.constraintlayout.widget.ConstraintHelper
import androidx.constraintlayout.widget.ConstraintLayout

class ConstraintRadioGroup @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ConstraintHelper(context, attributeSet, defStyleAttr) {

    private var radioButtonGroup: List<CompoundButton> = emptyList()

    override fun updatePreLayout(container: ConstraintLayout?) {
        super.updatePreLayout(container)
        container ?: return

        radioButtonGroup = mIds.take(mCount)
            .mapNotNull { container.findViewById(it) as? CompoundButton }
            .onEach { it.setOnCheckedChangeListener(listener) }
    }

    private val listener: CompoundButton.OnCheckedChangeListener =
        CompoundButton.OnCheckedChangeListener { button, isChecked ->
            clear()
            button.isChecked = isChecked
        }

    private fun clear() {
        radioButtonGroup.map { it.isChecked = false }
    }
}

使いたいところで app:constraint_referenced_ids に RadioButton の id を渡してあげれば同一のスコープ(リスナー)として扱うことができます。

<xxx.xxx.xxx.ConstraintRadioGroup
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:constraint_referenced_ids="radio1, radio2, radio3, radio4" />

注意点

ConstraintHelper 自体は ConstraintLayout 1.1.0 で追加された機能ですが、上記の拡張クラスは 1.1.2 でなぜか動作しませんでした🤔
2.0.0〜で使うことをお勧めします。