アプリの画面サイズを取得したい場合があります。タブレットとスマホで表示を変えたい。あるいはテキストの位置を正確に表示したいなど
実際にアプリで使える画面サイズとスクリーン全体のサイズは異なり Status bar、Title bar、Navigation bar を考慮しないといけません。
2021.1.1
Display
Display | Android Developersでは表示領域として以下の3つについて説明されています。
physical size of the display
- 物理的な画面のピクセルサイズ
real display area
- Status bar,、Title bar、Navigation barなどのアプリケーション装飾を含む表示領域
application display area
- アプリケーション装飾を除きapplication windowを含めた表示領域
Screen size
API29まで画面サイズを取得するには以下のようにしていましたが、これが非推奨になりました。getDefaultDisplay()
1 2 3 4 5 6 7 8 |
WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE); Display disp = wm.getDefaultDisplay(); Point realSize = new Point(); disp.getRealSize(realSize); int ScreenWidth = realSize.x; int ScreenHeight = realSize.y; |
API30からは getWindowInsets() を使います。これは、Status barとNavigation barも調べられます。
1 2 3 4 5 6 7 8 |
WindowMetrics windowMetrics = this.getWindowManager().getCurrentWindowMetrics(); Insets insets = windowMetrics.getWindowInsets() .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()); int ScreenWidth = windowMetrics.getBounds().width(); int ScreenHeight = windowMetrics.getBounds().height(); int StatusBar = insets.top; int NavigationBar = insets.bottom; |
landscapeの場合はtop, bottomがleft, rightになる
Layout area
アプリで実際使えるレイアウト領域は、Screen sizeからTitle barやStatus barそれにNavigation barを差し引いた領域になります。
これはLayoutから求めたり、Viewなどを最大にして画面に張り付けてそこから求めることもできます。
1 2 3 4 5 6 7 8 |
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); LinearLayout layout = findViewById(R.id.activity_main); int layoutWidth = layout.getWidth(); int layoutHeight = layout.getHeight(); } |
この時のレイアウトファイル
activity_main.xml
1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> </LinearLayout> |
デフォルトでactivity_main.xmlにidが振られているのでそれを使ってレイアウトの縦横サイズを取得します。ただし、これはonCreate()のタイミングでは取れないのでfocusが変わったことろで取り出します。
1 2 3 4 5 |
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); ... } |
Status barとNavigation barはgetWindowInsets()で取り出せました。
Title bar はこのLayout area を使って Title barの有無でその差分から計算できます。
Title barを非表示するにはAppCompatActivityをActivityに変更するか
ThemeでNoActionBarを選択するとできます。
Pixel 4 XL | height (pixel) |
Title bar 無し | 2700 |
Title bar 有り | 2504 |
Title bar | 196(56dp) |
Googleの端末で Portraitではこのようになっていました。
Pixel 3a | Pixel 3XL | Pixel 4 | Pixel 4XL | |
Resolution (pix) |
1080 x 2220 |
1440 x 2960 |
1080 x 2280 |
1440 x 3040 |
dip scale | 2.75 | 3.5 | 2.75 | 3.5 |
Resolution(dp) | 393 x 807 | 411 x 846 | 393 x 829 | 411 x 869 |
Aspect Ratio | 9 : 18.5 | 9:18.5 | 9 : 19 | 9 : 19.5 |
Size | 5.6″ | 6.3″ | 5.7″ | 6.3″ |
Density | 441dpi | 560dpi | 440dpi | 560dpi |
Status bar | 66(24dp) | 172(49dp) | 171(62dp) | 172(49dp) |
Title bar | 154(56dp) | 196(56dp) | 154(56dp) | 196(56dp) |
Navigation bar | 132(48dp) | 168(48dp) | 132(48dp) | 168(48dp) |
(注)実機での実測テストをしていないものもあります
サンプルテストコード
このコードでテストしました。
Activity と AppCompatActivityの2ケースでテスト
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
//package com.example.testscreensize; import android.app.Activity; import androidx.appcompat.app.AppCompatActivity; import android.graphics.Insets; import android.os.Bundle; import android.util.Log; import android.view.WindowInsets; import android.view.WindowMetrics; import android.widget.LinearLayout; public class MainActivity extends Activity { //public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); float dp = getResources().getDisplayMetrics().density; Log.d("log","dp="+dp); // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) WindowMetrics windowMetrics = this.getWindowManager().getCurrentWindowMetrics(); Insets insets = windowMetrics.getWindowInsets() .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()); int ScreenWidth = windowMetrics.getBounds().width(); int ScreenHeight = windowMetrics.getBounds().height(); int StatusBar = insets.top; int NavigationBar = insets.bottom; Log.d("log","ScreenWidth="+ScreenWidth); Log.d("log","ScreenWidth_dp="+ScreenWidth/dp); Log.d("log","ScreenHeight="+ScreenHeight); Log.d("log","ScreenHeight_dp="+ScreenHeight/dp); Log.d("log","StatusBar="+StatusBar); Log.d("log","StatusBar_dp="+StatusBar/dp); Log.d("log","NavigationBar="+NavigationBar); Log.d("log","NavigationBar_dp="+NavigationBar/dp); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); LinearLayout layout = findViewById(R.id.activity_main); int layoutWidth = layout.getWidth(); int layoutHeight = layout.getHeight(); Log.d("log","layoutWidth="+layoutWidth); Log.d("log","layoutHeight="+layoutHeight); } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> </LinearLayout> |
Appendance
physical size of the display:
ReferenceのDisplayの中にある
physical size of the displayはどうすれば取り出せるのでしょう。
adb コマンドにwmがあるので、おそらくwindow managerのことでしょうか
1 2 |
>adb shell wm size Physical size: 1440x2560 |
何気にそれらしい値が出てきました。
これを使うと任意のスクリーンサイズを試せるようです。
例えばadb shell wm size 2000×3000 とすると2000×3000の画面をエミュレートできるわけです。
1 2 3 4 5 |
>adb shell wm size 2000x3000 >adb shell wm size Physical size: 1440x2560 Override size: 2000x3000 |
Physical sizeは変わりませんがOverride sizeとして設定値が返ってきました。画面も大きくなっています
Display, DisplayMetricsでのサイズも
2000×3000
となりました。
尚、リセットしないと元に戻りません、実機では危険なので自己責任でやりましょう。
1 |
>adb shell wm size reset |
メーカーはこんなことを想定していないので、メモリ不足や様々な想定外の問題で落ちたり、復旧困難に陥る可能性があります。
References:
WindowInsets | Android Developers
WindowMetrics | Android デベロッパー | Android Developers
Display
DisplayMetrics