カスタムビューに独自のスタイル属性を定義する
メディアのサムネイルを同じ大きさで横一列に並べるコンテナクラスを作ったので、中にいれるサムネイルの数をレイアウトリソースで定義できるようにした。
res/values/attr.xml
にdeclare-styleable
を追加する
<resources> <declare-styleable name="MyCustomView"> <attr name="thumbCount" format="integer" /> </declare-styleable> </resources>
layoutリソースファイルで次のように使う
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" > <com.freshdigitable.MyCustomView android:id="@+id/custom_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" app:thumbCount="4" /> </LinearLayout>
独自のネームスペースを定義しようとしたら、「gradleプロジェクトではapp:.../res-auto
を使え」的なことを言われた気がする。
カスタムビューのコンストラクタで設定した値を受け取る
(色々と省略している)
public class MyCustomView extends View { private final int thumbCount; public MyCustomView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView, defStyle, 0); try { this.thumbCount = a.getInt(R.styleable.MyCustomView_thumbCount, 0); } finally { a.recycle(); } } }
TextViewをextendsする
View
を継承して自分のカスタムビューを作ろうとする時、3種類のコンストラクタをオーバーライドしなければならない。今までは何も考えずに
public HogeView(Context context) { this(context, null); } public HogeView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public HogeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
などとしていたが、TextView
などのandroid.R.attr.xxxStyle
があるものについては、引数が2このコンストラクタの中を
public MyCustomTextView(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.textViewStyle); }
のようにしなければならない。
TextView
はsupport-libの中にAppCompatTextView
があるのでこれを継承する。というか、他のTextView
と同じ色にならなくてなんでだろうな〜スタイルとかいじってないつもりなのにな〜とAppCompatTextView
のソースを読んでいたところこの事実に気づいた。引数3つのやつでsuper
を呼ぶより、それぞれのコンストラクタの中でsuper
を呼んで、さらにinit(Context, AttributeSet, int)
みたいな初期化メソッドを用意して呼んでやるのがこれからは良いのだろうか。
FloatingActionButtonのBackgroundTintにselectorを使うには
FloatingActionButton
にsetEnabled(false)
とかいう邪道なことをしようとしていて、状態に合わせて色を変えたかったのでcolorリソースのselectorを次のような感じで指定しようとした。
ColorStateList colorList = ContextCompat.getColorStateList(getContext(), R.color.selector); fab.setBackgroundTintList(colorList);
ところが、これでいざenabledをtrueとかfalseに変えてもずっとenabled=falseの色のまま変わらなかった。ボタン自体の状態は変わっているようで、enabled=falseの時はリスナに登録したアクションは起きないし、trueの時はちゃんと起きる。
先にsetBackgroundTintMode(Mode)
を呼ぶといいという情報を見て試したり、ViewCompat.setBackgroundTintList()
を試してみたが効果はなかった。
調べているといろんなバグレポートが見つかるので、いまちゃんと動かないのかなと半ば諦めていたが、layoutリソースにapp:backgroundTint=@color/selector
で指定することで思った通りの動きになった。最初にandroid:backgroundTint
を使おうとしてAPI Level 21以上でしか有効でないという警告が出たのでjavaソースのほうで解決しようとしたのが敗因だった。
app
パッケージの方もサジェストされてほしいものだ。
(support-lib: 24.0.0で確認)