Android の Drawable への着色について (Drawable tinting)
Android APIs を眺めていると “tint” って単語が良く出てきます (“android:backgroundTint” とか “android:progressTint” とか) が、tint についてあんまり日本語の情報がなかったのでまとめてみます。
ちなみに “tint” の英語としての意味は、名詞で 「色合い」 とか 「染料」、動詞だと 「色を付ける」 や 「染める」 などです。
このエントリの内容
Drawable への着色 (Drawable tinting)
API level 21 から、Drawable リソースをアルファマスクとして定義し、その Drawable に色を付けて表示する、ということができるようになりました。 同じ形で異なる色のアイコンを複数個用意したいというような場面で便利ですね。
Android 5.0(API レベル 21)以降では、アルファ マスクとして定義されたビットマップや 9-patch に色を付けることができます。 着色には、カラーリソースまたはカラーリソースに変換されるテーマ属性を使用できます(
ドローアブルの使用 | Android Developers?android:attr/colorPrimary
など)。
bitmapあるいはnine-patcheをアルファマスクとして定義しcolorリソースやテーマの属性で色づけする
L Developer Preview マテリアルデザイン - アニメーション - Firespeed
Drawable
クラスに、下記のメソッドが追加されています。
Drawable#setTint(int)
メソッドDrawable#setTintList(ColorStateList)
メソッドDrawable#setTintMode(PoterDuff.Mode)
メソッド
これらを使うことで、Drawable に着色することができます。
// 通常通り Drawable オブジェクトを取得し、#setTint メソッドや #setTintMode メソッドを呼ぶことで着色。 Drawable d = getDrawable(R.drawable.example); d.setTint(ContextCompat.getColor(this, R.color.exampleTint)); d.setTintMode(PorterDuff.Mode.SRC_IN); // 後はこの Drawable オブジェクトを使う。 imageView.setDrawable(d); // 例えば ImageView で表示する。
ちなみに、この機能が導入される前から、同様のことが Drawable#setColorFilter
メソッド で実現できていたようです。 setColorFilter
を呼んだ場合は、tint の設定は上書きされます。
Tint mode について
Drawable#setTintMode(PoterDuff.Mode)
メソッドでは、元の Drawable と Tint の色をどのように混ぜるかを Porter-Duff のルールで指定します。 元の Drawable が destination で、着色する色が source です。
デフォルトでは Source In Destination 規則 (PorterDuff.Mode.SRC_IN
) が使用されます。 これは、単純に tint が不透明な単色の場合、合成後の各ピクセルの不透明度は元の Drawable の不透明度になり、合成後の各ピクセルの色は tint の色になるというものです。 まさに Drawable がアルファマスクになるわけです。
Porter-Duff のルールについては以前このブログに書きました。 下記エントリを参照してください。
Support library による Drawable への着色のサポート
API level 21 から導入された Drawable への着色の機能ですが、v4 Support Library に含まれる DrawableCompat
クラスを使うことで、古い API level でも同様の機能を実現できます。
Drawable d = DrawableCompat.wrap(ContextCompat.getDrawable(this, R.drawable.example)); DrawableCompat.setTint(d, ContextCompat.getColor(this, R.color.exampleTint)); DrawableCompat.setTintMode(d, PorterDuff.Mode.SRC_IN);
対象の Drawable を DrawableCompat#wrap
メソッドに渡して tint 対応の Drawable に変換し、それを DrawableCompat#setTint
メソッドなどに渡す、という使い方になります。
Drawable への着色の応用
実際に Drawable への着色をしたい場面というのは、例えば View の背景に Drawable をセットしてその Drawable に着色するだとか、ImageView
で表示する Drawable に着色するだとか、あるいは ProgressBar
の (プログレスバーそのものを表す) Drawable に着色するだとか、そういう場面が多いでしょう。 そのような場面で簡単に Drawable への着色が行えるように、Java クラスのメソッドやレイアウトの XML で使える属性などが用意されています。
各 view の背景の Drawable への着色 (Background tint)
API level 21 で導入された下記のメソッドや XML 属性を使用して、簡単に背景の Drawable に着色できます。
View#setBackgroundTintList(ColorStateList)
メソッド- 対応するレイアウト XML の属性は
android:backgroundTint
- 対応するレイアウト XML の属性は
View#setBackgroundTintMode(PorterDuff.Mode)
メソッド- 対応するレイアウト XML の属性は
android:backgroundTintMode
- 対応するレイアウト XML の属性は
API level 21 未満の環境でこれらの機能が使えるように、v7 appcompat library が各種 compatible widget を提供しています。 (ただし、対応されている View のクラスは一部のみ。) よって、v7 appcompat library を使うことで、以下のようにして API level 21 未満の環境でも background tint を使用できます。
<!-- v7 appcompat library を使用していると、この TextView はインフレート時に AppCompatTextView に変換される。 --> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/example_text_view_background" app:backgroundTint="@color/exampleTextViewBackgroundTint"/>
ただ、上のような書き方をすると Android Studio でエラーが表示されるのが悩ましいところです。 (AppCompatTextView
への変換まで認識してくれないため。)
v7 appcompat library の compatible widget については以前エントリを書きましたので、詳しくは下記エントリを参照してください。
その他の Drawable の着色
ImageView
には、表示する Drawable に着色するためのメソッドが存在します。
ImageView#setImageTintList(ColorStateList)
メソッド- 対応するレイアウト XML の属性は
android:tint
- 対応するレイアウト XML の属性は
ImageView#setImageTintMode(PorterDuff.Mode)
メソッド- 対応するレイアウト XML の属性は
android:tintMode
- 対応するレイアウト XML の属性は
ProgressBar
でも Drawable への着色が可能です。
ProgressBar#setProgressTint(ColorStateList)
メソッド- 対応するレイアウト XML の属性は
android:progressTint
- 対応するレイアウト XML の属性は
ProgressBar#setProgressTintMode(PorterDuff.Mode)
メソッド- 対応するレイアウト XML の属性は
android:progressTintMode
- 対応するレイアウト XML の属性は
- など、各 Drawable に対応したメソッド (およびそれに対応する XML の属性) が定義されている
調べられていませんが、Drawable を扱う他の View クラスにも似たような機能があるかもしれません。
API level 21 未満でこのような機能を使えるようにする互換クラスは (今のところ) Android Support Library には含まれていないようですので、API level 21 未満では直接 Drawable に着色したうえで ImageView
にセットしたり ProgressBar
にセットしたりする必要がありそうです。
まとめ
- API level 21 から Drawable への色付けがサポートされました。 (Drawable tinting)
- 基本的には、アルファマスクとして Drawable を定義し、表示時に色を指定するという使い方が想定されています。
- View の背景の Drawable への着色や、
ProgressBar
やImageView
などで表示される Drawable への着色も簡単に行えるようになっています。 - Android Support Library を使うことで、Drawable への着色の機能や View の背景の Drawable への着色が API level 21 未満でも利用できます。
関連ページ
- 【Android】Support LibraryのVectorDrawableCompatが適応されるまでの仕組み - Qiita
- Drawable への着色ではなく Vector Drawable のサポートについてですが、内部でどういう処理がされているのか説明されています。 このエントリの内容とかぶっている部分もありますのであわせて読むと良さそうです。