Androidアプリから画面サイズを取得する方法

Androidアプリから画面サイズを取得する方法が、2.xと3.x以降で変わっていたのでメモしておきます。

実例

まずはテストアプリのスクリーンショットから。


表記の説明
  • layout root : View階層のルートのサイズ
  • DisplayMetrics : Context#getResources().getDisplayMetrics() で取得したサイズ
  • getDefaultDisplay : Activity#getWindowManager().getDefaultDisplay() で取得したサイズ
  • getDefaultDisplay raw : 3.x 以降で使える隠しメソッド、 Display#getRawWidth() で取得したサイズ(後述)
  • wallpaper: WallpaperManager.getInstance(activity).getDesiredMinimumWidth() で取得したサイズ

説明

Google Nexus で動かしてるので画面サイズは720x1280の筈なのですが、DisplayMetrics と getDefaultDisplay は両方共、端末の画像サイズと異なる数値を示しています。ホームボタン等を表示するナビゲーションバーの分を差し引いたサイズしか取得できません。2.xにはナビゲーションバーが存在しないため、互換性が考慮されたのだと思います。

画面全体のサイズを取得するには隠しメソッドを使う必要があります。なんでコレが非公開なのか…。

Display display = getWindowManager().getDefaultDisplay();
int raw_w = -1;
int raw_h = -1;
try{
	raw_w = (Integer)Display.class.getMethod("getRawWidth").invoke(display);
}catch(Throwable ex){}
try{
	raw_h = (Integer)Display.class.getMethod("getRawHeight").invoke(display);
}catch(Throwable ex){}

// 画面の向きによって、w,h が入れ替わっている場合があるようなので補正する
int orientation = getResources().getConfiguration().orientation;
if( orientation == Configuration.ORIENTATION_PORTRAIT ){
	if( rw > rh ){ int tmp = rw; rw = rh; rh = tmp; }
}else if( orientation == Configuration.ORIENTATION_LANDSCAPE ){{
	if( rw < rh ){ int tmp = rw; rw = rh; rh = tmp; }
}

3.xのシステムバーは非表示にすることができなかったのですが、4.xのナビゲーションバーは非表示にすることができます。View#setSystemUiVisibility() や View#setOnSystemUiVisibilityChangeListener() などのメソッドがあります。ただし、ナビゲーションバーを隠し続けたままユーザとのインタラクションを行うことはできません。画面をタップすると再度ナビゲーションバーが表示されます。

で、ナビゲーションバーを隠すとUIの再レイアウトが行われるのですが、「DisplayMetricsで取得できるサイズよりView階層のルートのサイズが大きくなる」という現象が発生します。これはひどい

一時的にでもナビゲーションバーを隠すことを想定したアプリでは、DisplayMetricsを信用してはいけない場合があるようです。フルスクリーンアプリを4.xに対応させる場合には気をつけた方がいいかもしれません。