2018年10月26日金曜日

FlexboxLayoutManager では CompoundDrawable の指定に relative 系の属性、メソッドは使わないほうがよい

compileSdkVersion 28, 27 で試しています(将来のリリースで修正されている可能性があります)。

FlexboxLayoutManager の問題ではなく、TextView の measure() 実装の問題です(Issue Tracker に登録しました)。
どういう問題かというと、setCompoundDrawablesRelativeWithIntrinsicBounds()setCompoundDrawablesWithIntrinsicBounds() で TextView の measure() の結果が異なり、setCompoundDrawablesRelativeWithIntrinsicBounds() だと measuredWidth/Height に CompoundDrawables のサイズが含まれないという問題です。 再現コードなどは上記の Issue に書いてあります。

FlexboxLayoutManager は MeasuredWidth/Height の値を使って View を配置しているため、TextView で setCompoundDrawablesRelativeWithIntrinsicBounds() や android:drawableStart, android:drawableEnd などで CompoundDrawable を指定すると、それを含まないサイズで配置され、文字が切れたり折り返して表示されてしまいます。



以下は RecyclerView + FlexboxLayoutManager の例です。



この例では、2行目は android:drawableLeft, android:drawableRight、4行目は android:drawableStart, android:drawableEnd を使っています。それ以外は同じです。セットされているテキストも両方 "Hello Android" です。

2行目用のレイアウト <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@drawable/square" android:drawableRight="@drawable/square" /> 4行目用のレイアウト <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableEnd="@drawable/square" android:drawableStart="@drawable/square" /> android:drawableStart, android:drawableEnd を使った4行目では、CompoundDrawable のサイズが measuredWidth/Height に反映されず、その分文字の領域が小さくなって "Hello Android" の Android が切れたり、square の下のほうが切れたりしています。

このように CompoundDrawable を relative 系の属性、メソッドで指定すると問題があるため、setCompoundDrawablesWithIntrinsicBounds() や android:drawableLeft, android:drawableRight を使いましょう。