2012/03/07

Android:ナビゲーションバーがアプリ描画領域を狭めることへの配慮


前回のsw<N>dpで記載した"アプリ描画領域"について、もう一歩踏み込んで調査します。

<N>値にはレイアウトに最低限必要なサイズを指定します。
もし、<N>値に画面解像度の一辺(幅or高さ)を指定する場合は下記の点に注意しなければ
いけません。

<N>に指定する値は"アプリが利用できる画面領域"であり"解像度の一辺(幅or高さ)"では
ありません。
例えば、画面解像度が480px×800pxで画面密度がmdpiの端末をターゲットにした場合。
values-h800dpのリソースフォルダを用意すれば、システムがこれを参照することを期待
するかもしれませんが、おそらくこれは参照されません。
なぜなら、解像度で800dpが確保されていてもステータスバーやナビゲーションバーの領域が
アプリが利用できる画面領域を削るので、ほとんどの場合で解像度よりも小さな値となる
からです。

下記の設定値を持つ端末とリソースで動作確認してみます。
【エミュレータA:ナビゲーションバーなし
・解像度:480×800
・画面密度:mdpi(160dpi)
・ステータスバーの高さ:25dp
・ハードキー:搭載


【エミュレータB:ナビゲーションバーあり
・解像度:480×800
・画面密度:mdpi(160dpi)
・ハードキー:非搭載
・ステータスバーの高さ:25dp
・ナビゲーションバーの高さ:48dp


【リソース】
下記のリソースを持つ.apkを作成
res/values-h727dp/*
res/values-h775dp/*
res/values-h800dp/*

端末の解像度はどれも480×800です。
しかし、values-h800dpがリソースとして選択されることはありません。
これは、ステータスバー領域がアプリが利用できる領域を25dp削っているからです。

エミュレータAでは、ステータスバー領域分の25dpを削った残りが、アプリ描画領域(775dp)
になるのでvalues-h775dpのリソースが参照されます。

しかし、エミュレータBではh775dpのリソースは参照されません。
これは、エミュレータBがナビゲーションバーを表示しており、更に48dp削られるからです。
そのため、エミュレータBではvalues-h727dpのリソースが参照されます。

x<N>dpが導入された経緯や目的を考えれば正しい動作と言えます。


●ナビゲーションバーとアプリ描画領域

Android4.0ではナビゲーションバー領域を新設し、バック、ホームおよび最近使用したアプリを
表示するための仮想ボタンをここに表示しています。



Android4.0では ナビゲーションバー は必ず表示されるというわけではありません。
バックやホームなどのボタンをハードキーとして備えている端末では、ナビゲーションバー
の存在は冗長なのでこれをシステム側で非表示に設定します。

ナビゲーションバーはWindowManagerから取得できるDisplayMetrics値に影響します。

例えば、下記のような解像度を取得するコードはよく目にします。
DisplayMetrics metrics = new DisplayMetrics();  
this.getWindowManager().getDefaultDisplay().getMetrics(metrics);     
Log.d("yuki", "widthPixels=" + metrics.widthPixels);
Log.d("yuki", "heightPixels=" + metrics.heightPixels);

metrics.widthPixels, metrics.heightPixelsの戻り値は ナビゲーションバー の有無で
下記のように変化します。

【ナビゲーションバー無】
widthPixels=480px
heightPixels=800px

【ナビゲーションバー有】
widthPixels=480px
heightPixels=752px

DisplayMetrics値がナビゲーションバーの高さ分の影響を受けていることが分かります。
端末のスペックにある解像度とDisplayMetrics値で得られる解像度に差異が出るというこ
とです。

以上です。