Android の描画リソースによるグラデーションは粗い。
表示領域を広げてゆくと、16bit カラーのディスプレイが主流の頃によく見られたマッハバンドのような縞が発生してしまう。仕事で作ったアプリでグラデーションを多用したのだが、それをタブレット端末でテストした時、この縞が気になってた。
はじめは省メモリやパフォーマンスの観点から、Android OS 自体の制限事項として品質を落としているのだと諦めていた。しかし気まぐれに、「Android gradient quality」かでググってみたら、以下の記事を見つけた。
記事中のサンプルコードでは、Activity.getWindow メソッドで得られたウィンドウに対し、Window.setFormat メソッドを呼び出している。
パラメータは PixelFormat.RGBA_8888。リファレンスには説明がないけれど、名前から察するに、これはアルファ ブレンドありの 32bit カラーなのだろう。どうやらこれで、Activity の描画品質を変更できるらしい。
ちなみに Android 2.1 時点の Window.setFormat は、以下のように実装されている。
/** * Set the format of window, as per the PixelFormat types. This overrides * the default format that is selected by the Window based on its * window decorations. * * @param format The new window format (see PixelFormat). Use * PixelFormat.UNKNOWN to allow the Window to select * the format. * * @see PixelFormat */ public void setFormat(int format) { final WindowManager.LayoutParams attrs = getAttributes(); if (format != PixelFormat.UNKNOWN) { attrs.format = format; mHaveWindowFormat = true; } else { attrs.format = mDefaultWindowFormat; mHaveWindowFormat = false; } if (mCallback != null) { mCallback.onWindowAttributesChanged(attrs); } }
よって、規定の描画品質に何が設定されているのかは、Window.getAttributes メソッドから得られたインスタンスから分かる。
実際にデバッグ実行して値を調べたところ、WindowManager.LayoutParams.format に書かれているとおり、PixelFormat.OPAQUE が設定されていた。リファレンスに「System chooses an opaque format (no alpha bits required)」と説明されているが、これは 24bit カラーということなのだろうか。
ともあれ、描画品質を RGBA_8888 に設定することで、滑らかなグラデーションを描けることが判明した。
ここまでで調査完了なのだけど、せっかくなので、品質の変更がどれだけ描画に影響を及ぼすのかを検証するサンプル アプリを作成してみた。
はじめに表示される画面では、描画品質と色を選択する。ちなみにこの画面には RGBA_8888 を設定している。
品質は使用頻度の高そうな RGB_565 と RGBA_8888、ビットマップ操作時にメモリ節約のために選ばれることの多い RGBA_4444 を入れてみた。検証的には RGB_565 を OPAQUE にしたほうが良かったかもしれない。色は Paint.NET の標準パレット上から、私が好んで利用する配色を持ってきた。
メニューを選択して Show!! と書かれたボタンを押すと、選んだ内容に応じたグラデーションが表示される。
タイトルバー的な部分の光沢グラデーションも、画像ではなく描画リソースで定義している。スクリーンショットのとおり、RGBA_8888 以外の品質はかなり低い。
最後にサンプル アプリのプロジェクトを公開しておく。
TestGradientQuality.zip 18.4KB
Android 2.1 update 1 ( API Level 7 ) でビルドし、エミュレータと初代 Xperia ( SO-01B ) にて動作確認をおこなった。
なお、Xperia では RGBA_4444 モードの時、Activity が真っ黒になってしまった。同一バージョンの Android エミュレータでは表示できているので、端末のディスプレイ ドライバによってはサポートされていないモードがあるのかもしれない。