Android ではスクリーン上の長さを、抽象的な単位「dp」「sp」で表します。実際アンドロイドの画面サイズ解像度はメーカーによってまちまちですから、アプリを開発する側からすると何か便利な方法はないかと考えてしまいます。
解像度単位 dp, sp
Androidは様々なスクリーンサイズ(インチ)で、更に異なる画素数(ピクセル)のものが販売されていて、その1つ1つに合わせたレイアウト・デザインを作り込むのは大変です。
なので、解像度単位 dp, sp は画面サイズ、インチ数を包括し統一的に扱うことを目的とした抽象的な単位です。
例えば、ボタンの横幅を360dpに設定すると多くのスマホで「スクリーン横幅一杯のサイズになる」というような仕組みがあれば便利、というわけで、Googleさんが作ったのが dp とsp(フォント用)です。(実際はそれほど簡単とはいかないのではありますが)
Google Ref :
Supporting Multiple Screens
dp | dip, density-independent pixel | 抽象的な単位、mdpi (160 dpi) を基準とし、 mdpi のとき 1dp = 1px となる |
sp | scale-independent pixel | ユーザーが設定したフォントサイズに影響される |
px | pixel | ピクセル、物理的な表示用セル |
dpi | dots per inch | 1インチ幅のドット数、値が大きいほど1ドットの 物理的な大きさが小さくなり、よりきめ細かくなる。 |
DPIを取得するコード
1 2 3 4 5 6 |
DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); int dpi = metrics.densityDpi; // 別の方法 int dpi = getResources().getDisplayMetrics().densityDpi; |
DIPを取得する
1 2 |
// Get the screen's density scale final float scale = getResources().getDisplayMetrics().density; |
例えば
150dp => (int)(150 * scale)
となります
画面サイズ、dpi、dpの関係を表にすると
scale | スクリーンサイズ例 | |||
ldpi | 120[dpi] | 0.75 | 1[px] = 0.75[dp] | 240 x 320[px] |
mdpi | 160[dpi] | 1.0 | 1[px] = 1.0 [dp] | 360 x 640[px] |
hdpi | 240[dpi] | 1.5 | 1[px] = 1.5 [dp] | 540 x 960[px] |
xhdpi | 320[dpi] | 2.0 | 1[px] = 2.0 [dp] | 720 x 1280[px] |
xxhdpi | 480[dpi] | 3.0 | 1[px] = 3.0 [dp] | 1080×1920[px] |
xxxhdpi | 640[dpi] | 4.0 | 1[px] = 4.0 [dp] | 1440×2560[px] |
Googleの2018/1のデータでは xhdpi が一番多いようです
Screen Sizes and Densities
Screenサイズはhdpiでも、4インチ480×800、3.7インチ480×854などあります。スクリーン解像度のピクセル数とDPIが比例関係にはなく、画面の物理的大きさ(インチ数)も考慮されているということです。
Googleの解説を見てもそれぞれのサイズ定義の境界あたりはグレーな感じで、システム任せとも読み取れますが…
ちなみに こちらの方法で Pixel や Nexus のスクリーンサイズを取得するとこのようになります。
Pixel 2XL | Pixel XL | Pixel 2 | Pixel | |
Resolution(pixel) | 1440 x 2880 | 1440 x 2560 | 1080 x 1920 | 1080 x 1920 |
Density | 560dpi | 560dpi | 420dpi | xxhdpi |
dip scale | 3.5 | 3.5 | 2.625 | 3 |
Resolution(dp) | 411 x 822 | 411 x 731 | 411 x 731 | 360 x 640 |
Aspect Ratio | 1 : 2 | 9 : 16 | 9 : 16 | 9 : 16 |
Size | 5.99” | 5.5″ | 5.0″ | 5.0″ |
Nexus 6P | Nexus 5X | Nexus 4 | Nexus S | |
Resolution(pixel) | 1440 x 2560 | 1080 x 1920 | 768 x 1280 | 480 x 800 |
Density | 560dpi | 420dpi | xhdpi | hdpi |
dp scale | 3.5 | 2.625 | 2.0 | 1.5 |
Resolution(dp) | 411 x 731 | 411 x 731 | 384 x 640 | 320 x 533 |
Aspect Ratio | 9 : 16 | 9 : 16 | 3 : 5 | 3 : 5 |
Size | 5.7” | 5.2″ | 4.7″ | 4.0″ |
以前は360dp x 640dpを基本として考えて例外を調整するなどで対応していたりしましたが、410dp x 730dp 以上が出てきたので対応が必要になりましたね。
SPサイズはユーザー設定で変わる
SPのサイズはユーザーが設定でフォントサイズを設定でき、それによってスケーリングされます。
スマホの [設定] -> [ディスプレイ] -> [フォントサイズ]
このため、spで設定した文字は、ユーザーのフォントサイズによって変化します。
1 2 |
textView.setTextSize("ABC"); textView.setTextSize(18); // 18sp |
レイアウトはspサイズになりますが、ユーザーがフォントサイズを変えると画面上で大きくなったり小さくなったりします。
それでは、狙った画面レイアウトができません
それを阻止するためには
1 |
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); |
のように COMPLEX_UNIT_DIP を入れ
TypedValue
を設定する必要があります。
あるいは画像として文字を入れてしまうのも手です、dpとしての縛りがありますが
ただ、ユーザーが老眼だったりすると文字が小さくて見えないという不満がでるでしょうね…その辺も考慮する必要もあります。