2014年6月6日金曜日

【Android】テキストサイズが端末によっておかしくなる場合があるときに

Androidアプリには
/res/values/dimens.xml
という数値(サイズ)を一括で設定しておくファイルがある.


Viewの幅,高さややフォントサイズなど
ソースコード内にサイズをマジックナンバーで書くのは躊躇われる.
そんなときにこのdimens.xmlに記述して各レイアウトファイルやソースコードから呼び出す.

上で数値(サイズ)と書いたが,
ただ単なる数値(データ)は別のリソースxmlにintegerをどうぞ.

この/res/values/dimens.xmlはプロジェクト生成時に作られてるはず.
見てもらうとDIPやSP,PX等単位をつけることができるのが分かる.

dimens.xmlに記載された値をソースコードから取得するには
getDimension()やgetDimensionPixelSize()といったメソッドを使うのだが,
以下の例のような点に注意してほしい.

例:
・/res/values/dimens.xmlで↓のように定義する
 <dimen name="hoge16dip">16dip</dimen>

・Javaからそれを取得する
 getDimension (R.dimen.hoge16dip);

このときgetDimensionして得た値は16ではない(可能性が高い)

getDimensionすると,画素密度に応じてピクセルサイズに直してくれ,
その値が取得できるのである.
つまり,得られる値は以下のとおりである.
mdpi(1x): 16
hdpi(1.5x): 24
xhdpi(2x): 32
xxhdpi(3x): 48
取得できる値は画素密度倍率を計算済みのピクセルだ.

16DIPのリソースをgetDimensionして16が得られるのは端末がmdpiのときのみである.

これはバグか?
いいや,これが正しい動きなのである.
端末の解像度の差異を気にしなくていいため
このほうが殆どの場合で嬉しい動きなのだ.
そうでないとgetDimensionでサイズ値を取得した後に
画素密度倍率を取得,表示すべきサイズを計算しなくてはいけなくなる.

ちなみにフォントサイズを指定するときに推奨されている単位はDIPじゃなくてSP.
このSPという単位はDIPにさらに端末のフォントサイズ設定を反映させたもの.
これがさらに問題をややこしくさせる場合がある.
今回はとりあえず(゚ε゚)キニシナイ!!

ここまでを踏まえて以下のことに注意してほしい.
TextView::setTextSize(float size)というテキストのサイズを指定するメソッドは
このままでは引数をSP値として扱う.

<dimen name="hoge16sp">16sp</dimen>
というリソースに対して

float size = getDimension (R.dimen.hoge16sp); // テキストサイズだから16SPにしてるよ
textView.setTextSize(size);

↑こんなことはしてはいけない.

全て画角を5インチに合わせてプレビューを作ってみた.
同じ5インチでも解像度が高くなると画素密度も高くなる.
見ての通り画素密度があがるにつれフォントが大きく見えるようになる.
(何故かXXHDPIでは文字が崩れた)
こんなのでは実用に耐えない.





解決方法は
TextView::setTextSize(int unit, float size)メソッドを使うこと.
先に述べたとおりgetDimensionで得られる値はその端末用に計算されたピクセル値なので
ここでunitにTypedValue.COMPLEX_UNIT_PXを指定する.

float size = getDimension (R.dimen.hoge16sp);
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);

これで端末解像度が変わってもサイズはあまりかわらないようになった.




0 件のコメント:

コメントを投稿