問題
booleanを使ってandroid:background
の値を制御するようなレイアウトを書いたとします。
<data> <variable name="focused" type="boolean" /> </data> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@{focused? @drawable/shape_focused : null}" >
この時Data Binding Libraryが以下のようなコードを吐きます。
this.mboundView1.setBackground((android.graphics.drawable.Drawable) FocusedAndroidDrawableShapeFocusedObjectnull);
アプリのminSdkVersionが16未満の場合Lintに以下の様に怒られてしまいます。
NewApi: Calling new methods on older versions
View#setBackground(Drawable)
のAPI Levelが16だからですね。@TargetApi
等で分岐しろと言われます。
対応
さて、Bindingクラスは自動で生成されるので@TargetApi
を追加できません。こういう時はBindingAdapterアノテーション
を使います。BindingAdapterアノテーション
は属性値のバインド処理を定義できるアノテーションです。どこか適当な場所(アプリケーションID.databinding
などが望ましいかもしれません)にViewGroupAdapter
というクラスを作ります。
public class ViewGroupAdapter { @BindingAdapter("android:background") public static void setBackgroundAdapter(ViewGroup viewGroup, Drawable drawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { setBackground(viewGroup, drawable); } else { setBackgroundDrawable(viewGroup, drawable); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public static void setBackground(ViewGroup viewGroup, Drawable drawable) { viewGroup.setBackground(drawable); } public static void setBackgroundDrawable(ViewGroup viewGroup, Drawable drawable) { viewGroup.setBackgroundDrawable(drawable); } }
ViewGroupAdapter
は"android:background"を処理するメソッドを定義しています。対象をViewGroupにしているのでFrameLayoutにも適用されます。ImageViewなどViewGroupと継承関係のないViewへは適用されないのでご注意ください。
このクラスを定義して再度コンパイルすると生成されるコードが以下のように変化します。これでLintに怒られずにすみますね。
アプリケーションID.databinding.ViewGroupAdapter.setBackgroundAdapter(this.mboundView1, (android.graphics.drawable.Drawable) FocusedAndroidDrawableShapeFocusedObjectnull);
最後に
BindingAdapterアノテーション
はアプリケーション全体に適用されるので適当にやりすぎると確実に事故ります。用法用量を守って活用しましょう。
ところでC88でTechBooster本に参加しています。Data Binding Libraryについて根掘り葉掘り書いたのでよかったら買ってください。