さて。
端末でアプリを実行すると、「画像表示(View)が拡大されてしまう」不具合について。
(参照:「画面サイズ設定」ってナニよ?)
原因は、画面サイズだと思ったんだけど、そうではなかったみたい。
振り出しに戻る…。
でも、ヒントはあった。
それが「ピクセル密度」。
「ピクセル密度」ってナニよ?
ピクセル密度は、「1dotを何pixelで表すか?」というもの。
何の役に立つのかというと、「表示されるものは、どの環境でも、同じ大きさで表示される」。
17インチモニターでも、15インチモニターでも、そこに表示されるものは、同じ大きさになるってワケ。
じゃ、なんで、画像が拡大表示しまうのか?
それは画面と画像のピクセル密度が合っていないから。
画像のピクセル密度が、画面の密度より低いため、拡大表示されてしまうんだ。
PhotoShopやGIMPなんかで、印刷解像度を低くした時と似てる。
「ピクセル密度 = 印刷解像度」みたいに捉えるとわかりやすいかもね。
Androidでの表示は、WYSWYGの仕組みに近いんだ。
ピクセル密度を調べる
ピクセル密度は、下記の方法で調べられる。
実行すると、ログにピクセル密度が書き出されるよ。
DisplayMetrics metrics = getResources().getDisplayMetrics(); Log.d( "TEST", "density=" + metrics.density );
DisplayMetrics では、画面に関する他の情報も取得できる。
DisplayMetrics metrics = getResources().getDisplayMetrics(); Log.d( "TEST", "density=" + metrics.density ); Log.d( "TEST", "densityDpi=" + metrics.densityDpi ); Log.d( "TEST", "scaledDensity=" + metrics.scaledDensity ); Log.d( "TEST", "widthPixels=" + metrics.widthPixels ); Log.d( "TEST", "heightPixels=" + metrics.heightPixels ); Log.d( "TEST", "xDpi=" + metrics.xdpi ); Log.d( "TEST", "yDpi=" + metrics.ydpi );
ちなみに。
「画面サイズ設定ってナニよ?」で画面サイズを調べた時、画面サイズは 533×400 だった。
それぞれに、ピクセル密度:1.5 をかけると、800×600 になる。
ちょうど、normalScreens での値とlargeScreens での値になるね。
画像リソースのピクセル密度設定(画像解像度設定)
拡大表示される原因は、ピクセル密度の違いにあることがわかった。
じゃ、画面のピクセル密度に、画像のピクセル密度を合わせればいいワケだ。
でもソレってどうやるの…?
印刷解像度をいじくったリソースを使用してもダメ。
ピクセル密度は、画像リソースだけで行う設定じゃないんだ。
ピクセル密度の設定は、Eclipseプロジェクトでも行うんだ。
正確には、設定ではないんだけどね。(^_^;
大抵、画像リソースは、drawable ディレクトリに置くよね?
それと同じで、それぞれのピクセル密度のディレクトリに、最適化した画像リソースを置くんだ。
drawable-ldpi … 120dpi( low ) drawable-mdpi … 160dpi( medium ) drawable-hdpi … 240dpi( high )
たとえば、medium で533x400dot の画像の場合、drawable-hdpi に800x600dot に拡大した画像リソースを置く。
そうすることで、動作環境がdensityDpi = 240(high)だったら、画像リソースはdrawable-hdpi から使用される。
Android は動作環境に合わせて、それぞれから最適なピクセル密度のリソースを使用してくれるって仕組み。
最適なリソースがない場合、Android が自動的に拡縮調整してくれる。
ただし、基準はmedium(160dpi)。
つまり、drawable にだけ置くと、リソースをmedium として拡縮処理をしてしまう。
high(240dpi)の環境で表示すると、拡大表示されてしまうんだね。
これは便利な仕組みなんだけど…ゲームなんかでは困った仕組みだよ。
ゲームの場合、テレビのようにdpi調整はしないで欲しい…
この場合、drawable-nodpi ディレクトリにリソースを置く。
drawable-nodpi … dpi調整をしない
今回、drawable ディレクトリにあったリソースを、drawable-nodpi へ移すことで、拡大表示されてしまう不具合は解消されたよ。
プログラムからピクセル密度(画像解像度)を設定する
ピクセル密度は、リソース・ディレクトリで対応できることがわかった。
でも、ソレってデータがリソースの時だけ。
画像データを外部参照する時は…?
外部参照だけじゃなく、プログラム側からピクセル密度を設定したい場合もあるよね。
そこでピクセル密度を設定できるか、ざっと調べてみたよ。
◆Canvas
int getDensity() void setDensity(int density)
http://developer.android.com/reference/android/graphics/Canvas.html
◆Bitmap
int getDensity() void setDensity(int density) int getScaledHeight(int targetDensity) int getScaledWidth(int targetDensity)
http://developer.android.com/reference/android/graphics/Bitmap.html
◆BitmapDrawable
void setTargetDensity(int density) void setTargetDensity(DisplayMetrics metrics) void setTargetDensity(Canvas canvas)
http://developer.android.com/reference/android/graphics/drawable/BitmapDrawable.html
以上からすると、今回の不具合には、Viewで使ってるCanvas にピクセル密度を設定すればいいみたい。
そこでこんな風↓にしてみたよ。
Canvas canvas; Bitmap scrImg = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 ); scrImg.setDensity( 160 ); Log.d("TEST", "scrImg density = " + scrImg.getDensity() ); Canvas scrImg_canv = new Canvas( scrImg ); // scrImg_canv.setDensity( 160 ); Log.d("TEST", "Canvas density = " + scrImg_canv.getDensity() );
Canvas に直接、設定するのではなく、元になるBitmap の密度を設定してみた。
Bitmap の設定がCanvas に引き継がれるか、確かめたかったため。
実行してみると、設定値はちゃんと引き継がれていた。
表示する画像データは、drawable ディレクトリに置いた画像リソース。
medium(160dpi) と認識されるので、setDensity で設定する値も160にしてある。
以上で、拡大表示される不具合は解消できたよ。
この設定は、他のことにも使えそう。
たとえば、動的に値を変えて、拡縮操作の代わりにするとか。
まぁ、setBounds の方が使い勝手はいいから、意味はないだろうけどね。(^_^;