どくぴーの備忘録

真面目なことを書こうとするクソメガネのブログ。いつ投げ捨てられるのかは不明

今更「dp」について考える

この記事は 飲酒プログラミング Advent Calendar の15日目の記事です。

どーも。どくぴーです。

会社の方で、デザイナーの方に「dpがよくわからない…、というかAndroidって画面サイズバラバラだけどiPhone SE(1st gen)みたいな小さい画面みたいな考えってあるんですか?」という質問を頂き、せっかくなので今更dpを考え直してみようと思いました。 これはスライドの要点の書き起こしであり、スライドだけを見れば十分な場合が多そうです。



導入

f:id:e10dokup:20201214220732j:plain:w640

僕が仕事をする上で、デザイナーさんがiOSアプリのデザインをされている時に「小さい画面のデザイン」というと、横幅320pxの画面に対するデザインのことだと考えています。ではAndroidではどうでしょうか。

f:id:e10dokup:20201214220932j:plain:w640

物理的に小さいデバイス…、って言うと。最近だと楽天モバイルで販売されているRakuten Miniがありますよね。ほかにも小さいデバイスなんていっぱいありました。でもそれはデザイナーの方が言うところの「小さい端末」でしょうか?という話です。

f:id:e10dokup:20201214221227j:plain:w640

dpとは?

Androidの画面デザインでは、昔から dp を用いています。これはdensity-independent pixels(密度非依存ピクセル)の略で、dipとも呼ばれたりします。この単位のおかげで、多種多様なAndroidバイスの画面サイズ・解像度において、(ある程度は)同じ表示ができるようサポートができるわけです。

f:id:e10dokup:20201214221449j:plain:w640

f:id:e10dokup:20201214221527j:plain:w640

f:id:e10dokup:20201215000557j:plain:w640

f:id:e10dokup:20201214221613j:plain:w640

dpにまつわる単位としては、デバイスそのものの画面解像度になるpx(pixel)、1インチ幅にどれだけのドットがあるかを示し、hdpiとかxxxhdpiとかの汎用密度に分類することのできるdpi(dots per inch)、そして本題のdp、フォントサイズの指定に使うsp(scale-independent pixels:スケール非依存ピクセル)等が挙げられます(pt/mm/inもありますがここでは一旦見なかったことにします)。px/dpi/dpについては

px = dp * (dpi / 160)

の関係が成り立ちます。画像リソースのサイズには

  • mdpi → 1倍
  • hdpi → 1.5倍
  • xhdpi → 2倍
  • xxhdpi → 3倍
  • xxxhdpi → 4倍

のような倍率で指定していましたが、これはあくまで上の式「dpi / 160」の形式化をしたものであるというわけで、実際に1dpが各端末のデバイス上で厳密に何pxになるか、という意味だと必ずしもこれらには一致しないと認識しています。

また、spはdpと似たような挙動をしますが、「ユーザのフォントサイズ設定」に応じて表示サイズに倍率がかかるので、アクセシビリティ等を観点に含めればより重要な値となります。

では、「小さい端末」ってなんだろう

少し前の話かもしれませんが、Androidの画面サイズ(16:9のとき)は一般的にはdpで表記すると 360 x 640dp であるという話でした。

f:id:e10dokup:20201214222758j:plain:w640

例えば、Sony XPERIA XZの画面サイズをdpで表記するとたしかにxxhdpiで360 x 640dpです。

f:id:e10dokup:20201214222828j:plain:w640

一方、物理的に小さい端末のはずのRakuten Miniも計算してみるとxhdpiでこちらも360 x 640dpになりました。

つまりRakuten Miniは「(デザイン的には)別に小さい端末とは言えない」という話になります。

逆に大きいデバイスで考えてみると、Nexus 6/Nexus 5Xあたりを皮切りに360dpより横幅の大きい端末が出てきました。

f:id:e10dokup:20201214223059j:plain:w640

例えばPixel 3を見てみると、xxhdpiですが px = dp * (dpi / 160) の (dpi / 160) に相当する部分が2.75になるので、392 x 786dpという画面サイズが得られます。

以下のサイトを見ていると、特に最近出た端末なんかは (dpi / 160) の値が整数ではなくなってきた感じがあるので、そこらへんが大きな変化なのかなぁと思います。

yesviz.com

ちなみに1/1.5/2/3/4ではなくなったら「mdpi/hdpi/xhdpi/xxhdpi/xxxhdpiはもう用済みなのか」というとそういうわけではなくて、やはり画像リソース(非Vector Drawable)を使用する際は適切なリソースサイズを配置する必要があるので依然大事な値だと考えています。

f:id:e10dokup:20201214223620j:plain:w640

しかしここまで360dpより小さい値が出てこなかったので、「もしかしてAndroidにおいて小さい端末というのはもう存在しないのでは…?」というとそうではありません。Android 7.0以降から、ユーザ補助 > 画面サイズで画面をスケールさせることができ、これを最大にしたとき、画面の横幅が320dpになります。ある意味ではこれがAndroidにおける「小さい画面」の回答であり、どの端末でも適用可能なので、横幅320dpでの表示には気を使う必要がありそうです。

f:id:e10dokup:20201214223913j:plain:w640

逆に縮小して画面幅を広げることも可能で、そちらでは領域不足の表示崩れ…が起きるわけではないとは思いますが、実際にどのように表示されるかはチェックしておくべきでしょう。

エンジニアとしてどう気をつけるべきか

f:id:e10dokup:20201214224036j:plain:w640

Android Studio 4.0からLayout Validatorが搭載されました。これによって、実際に手元にデバイスが揃っていなくとも、擬似的に様々な画面での表示を検証することができます。少し話はそれますがフォントサイズ設定や色弱の方向けの比較表示も可能なので、アクセシビリティ的な対応を行う意味でも使いこなすメリットは大きいでしょう。

f:id:e10dokup:20201214224226j:plain:w640

また、adbコマンドを使ってWindowManagerを操作し、実機上で表示がどのように変化するか検証することも可能です。これらによって「320dp以下ではどうしてもレイアウトの実現が厳しい」という話になるのであれば、 sw320dp のような設定修飾子を付与したdimens/layoutディレクトリを用意することで、各マージンやレイアウトそのものを切り分けるのが対策として考えられそうです。

終わりに

f:id:e10dokup:20201214224448j:plain:w640

久々にdpやAndroidの画面周りについてガッツリ調べてみたのですが、「以前よりもめんどくさくなってない…?」という感じでした。Pixel 3でdp -> pxの倍率がxxhdpiだから3…というわけではなく2.75になっているのは言われてみると「確かに…」という感じにはなるんですが普通に見落としていたので、デザイナーさんにわかりやすく説明しようと思う過程で自分の勉強にもなりました。dp周りはAndroidの画面デザイン・画面実装の基礎だと思うのでしっかり把握して認識を合わせてきれいに無理なくレイアウトできるようになりたいものですね。

References

余談:お前飲酒したの?

資料を書いているときは流石に飲酒していないんですが、構想中は横浜ビールを、資料の執筆中は軽井沢高原ビールのワイルドフォレストを頂きました。どちらも好きなビールなので美味しかったです! ところでリモート環境下になって途端にお酒に弱くなったんですが僕だけでしょうか。