Custom View を作るときに気をつけること
Custom Viewの背景画像を変えたいときにちょっとやらかしたのでメモる٩( 'ω' )و
何が起こったか
Custom Viewを作って動的に背景画像を変えようとして切り替わらない(ように見える)現象に遭遇。
レイアウトファイルで指定していた背景をコードから動的に切り替えようとしたときに、なぜか切り替わらないように見える 😇
何がおかしいか皆さんも考えながらコードをご覧ください。
コード
レイアウトファイル (layout_custom.xml)
静的に赤丸のdrawableを背景に指定しています。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="@drawable/red_oval" android:layout_width="match_parent" android:layout_height="match_parent"> </LinearLayout>
CustomViewの本体コード (CustomView.kt)
初期化時に上記のレイアウトファイルを読み込んでいます。viewの生成が完了し、attachされたタイミングで動的に背景を黒丸に変更しています。
class CustomView : LinearLayout { constructor(context: Context?) : super(context) constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) init { LayoutInflater.from(this.context).inflate(R.layout.view_custom, this) } override fun onAttachedToWindow() { super.onAttachedToWindow() this.setBackgroundResource(R.drawable.black_oval) } }
現実
さて、上記コードを書いたときに私は背景は黒丸が出ることを期待していましたが、実際には赤丸が表示されています😩
何がダメだったのか
さて、ここまで読んでくれた皆さんは原因に気がついたでしょうか。
今回の原因はCustom Viewでlayout fileをinflateするときにrootを this
に指定しているため、this
= Custom Viewクラス (Linear Layoutを継承しているクラス)のchildとしてlayoutファイルからinflateしたviewたちがぶら下がる構成になっていました。そのため、コードから this
に対して黒丸に背景を変更しても、その上にいる赤丸を背景に指定しているview (layout fileの一番上の階層にいるview)の背景が重ねて描画されているため見た目的には何も変わらないと言うオチになっていました。
どうすればよかったか
ちゃんと正しいviewに対してアクセスして背景を変えてやりましょう。(本当はちゃんとviewにidつけたりすべきですがサンプルなので見逃してください😇)
override fun onAttachedToWindow() { super.onAttachedToWindow() this.getChildAt(0).setBackgroundResource(R.drawable.black_oval) }
これで無事黒丸背景になりました!٩( 'ω' )و