2011/02/13

Bitmapの透過率を変更する

WeatherNow 1.0.5ではAppWidgetの背景画像の透過率を自由に設定していますが、その方法の解説です。


いつも不思議に思っていたのですが、一部アプリのAppWidgetで「背景画像の透過率を設定で変更できる」ものがあります。普通のActivityですと

(レイアウトxmlの一部)

(Javaファイルの一部)

とやれば一瞬で終わる話なのですが、AppWidgetに何か表示するにはRemoteViewを挟まねばなりません。AppWidget上のImageViewに表示させるにはRemoteViewの「setImageViewResource」や「setImageViewBitmap」が提起されていますが、「setImageViewAlpha」的なものが存在しないため、透過率を直接設定することは不可能です(多分)。そこで今回はResourcesに仕込んだイメージファイルをBitmapに読み込み、そこで透過率を変更した上でAppWidgetに表示する方法を解説します。リソースに透過率をいくつも設定したイメージファイル置いてもいいんですけどね、パッケージの肥大化になるだけですよね。
こちらのサイトを見ているときに気付きました。
これ、どこ探しても載ってなかったんだよな...
偶然の閃きバンザイ

本題に入る前に、Androidで扱う16ビットの色情報について解説します。例えばTextViewでフォントの色を変更する時私は

と指定しています。私もあまりJavaに詳しくないので適当な説明となりますが、「0xff112233」は16ビットのintで「ff」が透過率(00-ff = 0-255、以下同様)、「11」が赤、「22」が緑、「33」が青の情報を表しています。かっこ内に記載しましたが16進法表記となっているのでその点は注意して下さい。
ここまで書いてお気付きの方がいらっしゃるかも知れませんが、Bitmapで透過率の変更とは「112233」はそのまま「ff」の部分だけを書き換えれば可能でした。

次にこの「0xff112233」を2進法表記にすると
「1111 1111 0001 0001 0010 0010 0011 0011 」となります。16進法の文字一つが2進法では0と1、4つの組み合わせで表されています。

やっと本題に入ります。
レイアウトxmlに関していじるものは特にありません。


以上です。これでBitmapの透過率を自由に設定できます。(主に透過率を上げる方向にですが。濃いものを薄くする方が良いと思います。)

まず1の部分についてですが、取得する色情報を
0xAA123456(1010 1010 0001 0010 0011 0100 0101 0110)
とします。これはint情報なのでそのままでは「305419896」となってしまうため、1で色情報の入っている右から24のビットを破棄するためビットを右に24個移動します。

0xAA123456 (1010 1010 0001 0010 0011 0100 0101 0110) が
0x000000AA (0000 0000 0000 0000 0000 0000 1010 1010) になる。

次に2の部分でこの透過情報から引き算で透過率を上げています。先に書いたように透過情報はintだと0-255で表され、0が完全透過、255が透過無しです。上の例の様に透過情報から100を引くと

0x000000AA (170, 0000 0000 0000 0000 0000 0000 1010 1010) が
0x00000046 (70, 0000 0000 0000 0000 0000 0000 0100 0110) になる。

そしてこれを3の部分で左に24個ビットをずらすことで色情報を持たない透過情報のみのintを得ることが出来ます。4,5の部分では左に8ビットずらした後元に戻すことで透過情報を持たない色情報のみのintを作成しています。最後にこの2つのintを合成することで、色は変わらず新たな透過情報を持ったintが完成します。後はこのBitmapをRemoteview#setImageViewBitmapで当てはめるだけです。