はじめに
TextViewにアイコンを入れた際、色を付けるときにdrawableTintを使いたいですが、API23以降なので、minSDKによっては使えません。
その解決法と学びを記します。
コード
@BindingAdapter("drawableTintCompat")
fun TextView.setDrawableTintCompat(color: Int) {
compoundDrawablesRelative.forEach {
it?.setColorFilter(color, PorterDuff.Mode.SRC_IN)
}
}
@BindingAdapter("drawableTintCompat")
fun TextView.setDrawableTintCompat(color: Int) {
compoundDrawables.forEach {
it?.setColorFilter(color, PorterDuff.Mode.SRC_IN)
}
}
<TextView
app:drawableTintCompat="@{@color/hogehoge}"/>
ポイント
sdk21以上であれば、RTLの関係でdrawableStart/Endが推奨されています。
馴染みのあるgetCompoundDrawables
はStart/Endで指定していると取得できないことがあるため、getCompoundDrawablesRelative
を使いましょう。
https://developer.android.com/reference/android/widget/TextView.html#getCompoundDrawablesRelative()
また、Databindingを利用する関係で、ActivityやFragmentで使う際はDatabindingUtilでinflateやbindをしてレイアウトを設定する必要があります。
(xmlをで囲んだだけではbindされないため、そのままsetContentViewとかをしてもdrawableTintCompatは動きません)
おまけ
塗る処理で、setColorFilterではなくsetTintを使う場合は注意が必要です。
@BindingAdapter("drawableTintCompat")
fun TextView.setDrawableTintCompat(color: Int) {
compoundDrawablesRelative.forEach {
it?.apply {
setTint(color)
setTintMode(PorterDuff.Mode.SRC_IN)
}
}
}
この場合、drawableに対して直接Tintをしているので、他で使っている同じdrawableリソースの色も変わってしまいます。
色が単色の場合・毎回定義している場合は問題ないですが、そうでない場合はmutate
を呼んで上げる必要があります。
@BindingAdapter("drawableTintCompat")
fun TextView.setDrawableTintCompat(color: Int) {
compoundDrawablesRelative.forEach {
it?.mutate()?.apply {
setTint(color)
setTintMode(PorterDuff.Mode.SRC_IN)
}
}
}
mutateについては、以下の記事に詳しく書かれています。
http://y-anz-m.blogspot.com/2010/10/androiddrawable-mutations.html
最後に
drawablesがnullになってるのはなんでだろう・・・。
と思っていたらまさか別の取得方法があったとは。
compoundDrawablesRelative、忘れないでしょう。