読者です 読者をやめる 読者になる 読者になる

ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

Android の Drawable への着色について (Drawable tinting)

Android アプリ ライブラリ

Android APIs を眺めていると “tint” って単語が良く出てきます (“android:backgroundTint” とか “android:progressTint” とか) が、tint についてあんまり日本語の情報がなかったのでまとめてみます。

ちなみに “tint” の英語としての意味は、名詞で 「色合い」 とか 「染料」、動詞だと 「色を付ける」 や 「染める」 などです。

このエントリの内容

  • API level 21 から使えるようになった Drawable への色付け (Drawable tinting) について説明します。
    • アルファマスクとして Drawable を定義し、表示時に色を指定するための機能です。
  • View の背景の Drawable への着色のための、あるいは ProgressBarImageView などで表示される Drawable への着色のためのメソッドXML の属性を紹介します。
  • これらの機能を API level 21 未満でも使用できるようにするための Android Support Library が提供するメソッドを紹介します。

Drawable への着色 (Drawable tinting)

API level 21 から、Drawable リソースをアルファマスクとして定義し、その Drawable に色を付けて表示する、ということができるようになりました。 同じ形で異なる色のアイコンを複数個用意したいというような場面で便利ですね。

Android 5.0(API レベル 21)以降では、アルファ マスクとして定義されたビットマップや 9-patch に色を付けることができます。 着色には、カラーリソースまたはカラーリソースに変換されるテーマ属性を使用できます(?android:attr/colorPrimary など)。

ドローアブルの使用 | Android Developers

bitmapあるいはnine-patcheをアルファマスクとして定義しcolorリソースやテーマの属性で色づけする

L Developer Preview マテリアルデザイン - アニメーション - Firespeed

Drawable クラスに、下記のメソッドが追加されています。

これらを使うことで、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 に着色できます。

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 への変換まで認識してくれないため。)

f:id:nobuoka:20160213200931p:plain

v7 appcompat library の compatible widget については以前エントリを書きましたので、詳しくは下記エントリを参照してください。

その他の Drawable の着色

ImageView には、表示する Drawable に着色するためのメソッドが存在します。

ProgressBar でも Drawable への着色が可能です。

調べられていませんが、Drawable を扱う他の View クラスにも似たような機能があるかもしれません。

API level 21 未満でこのような機能を使えるようにする互換クラスは (今のところ) Android Support Library には含まれていないようですので、API level 21 未満では直接 Drawable に着色したうえで ImageView にセットしたり ProgressBar にセットしたりする必要がありそうです。

まとめ

  • API level 21 から Drawable への色付けがサポートされました。 (Drawable tinting)
    • 基本的には、アルファマスクとして Drawable を定義し、表示時に色を指定するという使い方が想定されています。
  • View の背景の Drawable への着色や、ProgressBarImageView などで表示される Drawable への着色も簡単に行えるようになっています。
  • Android Support Library を使うことで、Drawable への着色の機能や View の背景の Drawable への着色が API level 21 未満でも利用できます。

関連ページ