アプリの画面サイズを取得したい事が時々あります。タブレットとスマホで表示を変えたい。あるいはテキストの位置を正確に表示したいなど。画面のサイズと言っても、タイトルバーがあるか無いかで異なってくるので確認してみました。
API 29
Screen Size
Display | Android Developersでは表示領域として以下の3つについて説明されています。
physical size of the display
- 物理的なLCDのピクセルサイズですね
real display area
- アプリケーション装飾を含む表示領域
- getRealSize(Point), getRealMetrics(DisplayMetrics)でサイズを取得できる
application display area
- アプリケーション装飾を除きapplication windowを含めた表示領域
- getRectSize(Rect), getRectSize(Rect), getMetrics(DisplayMetrics)でサイズ取得できる
- DisplayクラスのgetRealSize(Point), getRectSize(Rect), getRectSize(Rect)
- DisplayMetricsクラスのgetRealMetrics(DisplayMetrics), getMetrics(DisplayMetrics)
Display class
例えばgetRealSizeを使ってreal display areaのサイズを取得するにはこのようにします。
real display area
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 realScreenWidth = realSize.x; int realScreenHeight = realSize.y; |
application display areaも同様です。
1 2 3 4 5 6 7 8 |
WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE); Display disp = wm.getDefaultDisplay(); Point size = new Point(); disp.getSize(size); int screenWidth = size.x; int screenHeight = size.y; |
DisplayMetrics class
またDisplayMetricsでサイズを取得するにはこのようにします。
real display area
1 2 3 4 5 |
DisplayMetrics dMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getRealMetrics(dMetrics); int realScreenWidth = dMetrics.widthPixels; int realScreenHeight = dMetrics.heightPixels; |
application display areaも同様です。
1 2 3 4 5 |
DisplayMetrics dMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dMetrics); int screenWidth = dMetrics.widthPixels; int screenHeight = dMetrics.heightPixels; |
Layout area
さて、real display areとapplication display areはしかしながら実際使うレイアウト領域とは異なることがあります。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が変わったことろで取り出します。これで3つの表示ケース分けして
case 1: Status Bar + Title Bar + Navigation Bar
case 2: Status Bar + Navigation Bar
- AppCompatActivity -> Activity 変更
case 3: Navigation Bar
- AppCompatActivity -> Activity 変更
- AndroidManifestのthemeをFullscreenに変更
Ref: アプリのタイトルバーを非表示、全画面表示にする
Nexus 6P でサイズを取ってみた結果が下です。
![[Android] スクリーンサイズを取得する device 2017 01 04 191136 170x300 - [Android] スクリーンサイズを取得する](https://akira-watson.com/wp-content/uploads/2017/01/device-2017-01-04-191136-170x300.png)
![[Android] スクリーンサイズを取得する device 2017 01 04 185709 170x300 - [Android] スクリーンサイズを取得する](https://akira-watson.com/wp-content/uploads/2017/01/device-2017-01-04-185709-170x300.png)
![[Android] スクリーンサイズを取得する device 2017 01 04 185845 170x300 - [Android] スクリーンサイズを取得する](https://akira-watson.com/wp-content/uploads/2017/01/device-2017-01-04-185845-170x300.png)
case 1 (pixel) | case 2 (pixel) | case 3 (pixel) | |
real display area | 1440 x 2560 | 1440 x 2560 | 1440 x 2560 |
application display area | 1440 x 2392 | 1440 x 2392 | 1440 x 2392 |
layout area | 1440 x 2112 | 1440 x 2308 | 1440 x 2392 |
この結果からそれぞれのbarの高さが分かります。
height (pixel) | dp | |
Status bar | 84 | 24 |
Title bar | 196 | 56 |
Navigation bar | 168 | 48 |
他のGoogleの端末で Portraitではこのようになっていました。
(注)これらのデータは実機で実測テストしていません。またPixel 3, 3XLはエミュレータにおかしな点があるので推測値です。
Pixel 4 XL | Pixel 4 | Pixel ? | Pixel ? | |
Resolution(pixel) | 1440 x 3040 | 1080 x 2280 | ||
Density | – | – | ||
dip scale | – | – | ||
Resolution(dp) | – | – | ||
Aspect Ratio | 9:19 | 9 : 19 | ||
Size | 6.3” | 5.7″ | ||
Status bar | – | – | ||
Title bar | – | – | ||
Navigation bar | – | – | ||
Layout area(pix) | – | – |
Pixel 3 XL | Pixel 3 | Pixel 3a XL | Pixel 3a | |
Resolution(pixel) | 1440 x 2960 | 1080 x 2160 | 1080 x 2160 | 1080 x 2220 |
Density | – | – | – | – |
dip scale | 3.5 | 2.75 | – | – |
Resolution(dp) | 411 x 845 | 392 x 785 | – | – |
Aspect Ratio | 9:18.5 | 9 : 18 | 9 : 18 | 9 : 18.5 |
Size | 6.3” | 5.5″ | 6.0″ | 5.6″ |
Status bar | 172(49dp) | 132(48dp) | – | – |
Title bar | 196(56dp) | 154(56dp) | – | – |
Navigation bar | 168(48dp) | 132(48dp) | – | – |
Layout area(pix) | 1440 x 2712 | 1080 x 1893 | – | – |
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″ |
Status bar | 84(24dp) | 84(24dp) | 63(24dp) | 72(24dp) |
Title bar | 196(56dp) | 196(56dp) | 147(56dp) | 168(56dp) |
Navigation bar | 168(48dp) | 168(48dp) | 126(48dp) | 144(48dp) |
Layout area(pix) | 1440×2712 | 1440×2112 | 1080×1584 | 1080×1536 |
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″ |
Status bar | 84(24dp) | 63(24dp) | 48(24dp) | 36(24dp) |
Title bar | 196(56dp) | 147(56dp) | 112(56dp) | 84(56dp) |
Navigation bar | 168(48dp) | 126(48dp) | 96(48ddp) | 0 |
Layout area(pix) | 1440 x 2112 | 1080 x 1584 | 768 x 1024 | 480 x 680 |
Status bar: 24dp,
Title bar: 56dp,
Navigation Bar: 48dp
は決まっているようですが、同じピクセルでもDensityの違いで見え方もかわるということですね
サンプルテストコード
このコードでテストしました
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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
package your.package.name; import androidx.appcompat.app.AppCompatActivity; import android.graphics.Point; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.Display; import android.view.WindowManager; import android.widget.LinearLayout; import android.widget.TextView; public class MainActivity extends AppCompatActivity { //public class MainActivity extends Activity { private float dp; private TextView textView1, textView2, textView3; private int realScreenWidth, realScreenHeight, screenWidth, screenHeight, rswDp, rshDp, swDp, shDp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView1 = findViewById(R.id.text_view1); textView2 = findViewById(R.id.text_view2); textView3 = findViewById(R.id.text_view3); dp = getResources().getDisplayMetrics().density; // true: AppCompatActivity // false: AppCompatActivity -> Activity 変更 boolean flg = true; if(flg){ WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE); Display disp; if(wm != null){ disp = wm.getDefaultDisplay(); } else{ return; } // real diplay area Point realSize = new Point(); disp.getRealSize(realSize); realScreenWidth = realSize.x; realScreenHeight = realSize.y; rswDp = (int)(realScreenWidth/dp); rshDp = (int)(realScreenHeight/dp); // applicaton display area Point size = new Point(); disp.getSize(size); screenWidth = size.x; screenHeight = size.y; swDp = (int)(screenWidth/dp); shDp = (int)(screenHeight/dp); } else{ DisplayMetrics dMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getRealMetrics(dMetrics); realScreenWidth = dMetrics.widthPixels; realScreenHeight = dMetrics.heightPixels; rswDp = (int)(realScreenWidth/dp); rshDp = (int)(realScreenHeight/dp); getWindowManager().getDefaultDisplay().getMetrics(dMetrics); screenWidth = dMetrics.widthPixels; screenHeight = dMetrics.heightPixels; swDp = (int)(screenWidth/dp); shDp = (int)(screenHeight/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(); int lwDp = (int)(layout.getWidth()/dp); int lhDp = (int)(layout.getHeight()/dp); String[] title = { "--- Real diplay area ---\n", "--- Application diplay area ---\n", "--- Layout area ---"}; String[] keypara = {"width = ", "height = ", "width dp= ", "height dp= "}; int[] wh1 = {realScreenWidth, realScreenHeight, rswDp, rshDp}; int[] wh2 = {screenWidth, screenHeight, swDp, shDp}; int[] wh3 = {layoutWidth, layoutHeight, lwDp, lhDp}; String[] unit = {" pix\n", " pix\n", " dp\n", " dp\n"}; String str1 = "dp = " + String.valueOf(dp) + "\n\n"; StringBuilder sb1 = new StringBuilder(str1); sb1.append(title[0]); for(int i=0; i<4; i++){ sb1.append(keypara[i]); String str = String.valueOf(wh1[i]); sb1.append(str); sb1.append(unit[i]); } sb1.append("\n"); textView1.setText(sb1); String str2 = "--- Application diplay area ---\n"; StringBuilder sb2 = new StringBuilder(str2); sb1.append(title[1]); for(int i=0; i<4; i++){ sb2.append(keypara[i]); String str = String.valueOf(wh2[i]); sb2.append(str); sb2.append(unit[i]); } sb2.append("\n"); textView2.setText(sb2); String str3 = "--- Layout area ---\n"; StringBuilder sb3 = new StringBuilder(str3); sb1.append(title[2]); for(int i=0; i<4; i++){ sb3.append(keypara[i]); String str = String.valueOf(wh3[i]); sb3.append(str); sb3.append(unit[i]); } sb3.append("\n"); textView3.setText(sb3); } } |
activity_main.xml
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 |
<?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" android:background="#dfe" tools:context=".MainActivity"> <TextView android:id="@+id/text_view1" android:layout_marginTop="40dp" android:layout_marginStart="40dp" android:textSize="20sp" android:textColor="#000" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/text_view2" android:layout_marginStart="40dp" android:textSize="20sp" android:textColor="#00f" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/text_view3" android:layout_marginStart="40dp" android:textSize="20sp" android:textColor="#f00" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </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:
Display
DisplayMetrics