フルスクラッチ(写経)でRadioGroupとRadioButtonを実装してみた


Android 標準で用意されているViewをフルスクラッチで作ってみる(写経)試みをしてみた。

んで、今回はRadioGroupとRadioButtonをフルスクラッチで実装してみた。

とりあえず成果はGithubに置いてあります。

本記事に書いてあることもだいたいREADMEにまとめてます。

Full scratch RadioGroup and RadioButton

Android 6系のコードをBaseにフルスクラッチでRadioGroupとRadioButton的なViewを写経して実装してみた

「動機、実装前に気になったこと」の部分をカバーできる範囲の最低限の実装になってる

動機、実装前に気になったこと

RadioGroupとRadioButtonみたいにRadioButtonにClickListenerみたいなの設定しなくても、親のListenerに通知が来るって実装はどうやってるのか気になった

  • ViewGroup.OnHierarchyChangeListenerを使ってる
    • Viewの階層に変更があると呼び出されることをうまく使ってる
  • ViewGroup.OnHierarchyChangeListenerのonChildViewAdded method内で追加されるRadioButtonに対して内部で作ったCompoundButton.OnCheckedChangeListenerを設定してる
    • この内部で作ったOnCheckedChangeListenerのonCheckedChanged method内でRadioButtonのチェック状態やチェックしてるViewのidなどを変更している
  • 実際にはCompoundButton.setOnCheckedChangeWidgetListenerに設定してる
    • hideのAPIなので普通には使えない
    • http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/widget/CompoundButton.java#176
    • なんで普通のsetOnCheckedChangeListener使わないのかは、内部で設定してるListenerが上書きされると正常に動作しなくなるからだと思われる
    • javadocにも「This callback is used for internal purpose only.」って書いてあるからやっぱり内部実装用のListenerってことになる
    • hideだったので、FullScratchRadioButtonに同じように内部で使う用のListenerの口を用意してあげた

RadioButtonにidを振ってなくても各Buttonがそれぞれ別々のButtonとして認識されているのはどうやってるのか気になった

  • viewにidが振られていなかったらView.generateViewId methodでViewのidを作成して、setIdしてる
  • View.generateViewId methodはAPI Level 17から追加されたもので、それ以下のバージョンでどう生成してたのか
    • hashCode methodの戻り値をViewのidにしてた

実装してみてわかったこと

  • 動的にViewのidを生成するならView.generateViewIdを使うのが良さそう
  • ViewGroup側で子Viewのクリックイベント等をハンドリングしたい場合に、ListenerをセットしてもいいがListenerが上書きされる危険性はある
    • なので子ViewもCustom Viewにして別口のListenerを作る or setじゃなくてadd Listener的なものがあればそっちにセットするほうがいい
    • 特にRadioGroupとRadioButtonみたいに親と子が密接に関連してるものは
  • 親と子が密接?に関連しているViewを作る場合のノウハウを学ぶのに最適だった
  • ViewGroup.OnHierarchyChangeListener使えばCustom GroupView作って色々できそう

主な実装

Link