'Getting screen width on API Level 30 (Android 11): getDefaultDisplay() and getMetrics() are now deprecated. What should we use instead?
I currently calculate the screen width like this :
public static int getScreenWidth(@NonNull Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
Since these 2 functions (getDefaultDisplay() and getMetrics()) are now deprecated, what should we use instead ?
Solution 1:[1]
For calculating screen width minus any system bars, this should work:
public static int getScreenWidth(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();
Insets insets = windowMetrics.getWindowInsets()
.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars());
return windowMetrics.getBounds().width() - insets.left - insets.right;
} else {
DisplayMetrics displayMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
}
Note that this isn't exactly the same: testing this with the height produces different results, and I've been unable to replicate the old API's functionality with the new API (partly due to the behavior of the old API being a bit tricky to reason about and not always what you want, hence its deprecation). In practice, though, it should be good enough as a generic screen width for many things.
Solution 2:[2]
@RequiresApi(20)
inline val Fragment.windowHeight: Int
get() {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val metrics = requireActivity().windowManager.currentWindowMetrics
val insets = metrics.windowInsets.getInsets(WindowInsets.Type.systemBars())
metrics.bounds.height() - insets.bottom - insets.top
} else {
val view = requireActivity().window.decorView
val insets = WindowInsetsCompat.toWindowInsetsCompat(view.rootWindowInsets, view).getInsets(WindowInsetsCompat.Type.systemBars())
resources.displayMetrics.heightPixels - insets.bottom - insets.top
}
}
@RequiresApi(20)
inline val Fragment.windowWidth: Int
get() {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val metrics = requireActivity().windowManager.currentWindowMetrics
val insets = metrics.windowInsets.getInsets(WindowInsets.Type.systemBars())
metrics.bounds.width() - insets.left - insets.right
} else {
val view = requireActivity().window.decorView
val insets = WindowInsetsCompat.toWindowInsetsCompat(view.rootWindowInsets, view).getInsets(WindowInsetsCompat.Type.systemBars())
resources.displayMetrics.widthPixels - insets.left - insets.right
}
}
This requires androidx.core version 1.5.x
Solution 3:[3]
I guess I have successfully implement equivalent methods (improving @RyanM's) to deprecated one.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Deprecated older method for comparison.
DisplayMetrics outMetrics = new DisplayMetrics();
getDisplay().getMetrics(outMetrics);
Log.d("Upto API-29", String.format(
"(width, height) = (%d, %d)", outMetrics.widthPixels, outMetrics.heightPixels
));
// Newer methods.
Log.d("API-30+", String.format(
"(width, height) = (%d, %d)", getScreenWidth(this), getScreenHeight(this)
));
}
public static int getScreenWidth(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();
Rect bounds = windowMetrics.getBounds();
Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility(
WindowInsets.Type.systemBars()
);
if (activity.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE
&& activity.getResources().getConfiguration().smallestScreenWidthDp < 600
) { // landscape and phone
int navigationBarSize = insets.right + insets.left;
return bounds.width() - navigationBarSize;
} else { // portrait or tablet
return bounds.width();
}
} else {
DisplayMetrics outMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
}
public static int getScreenHeight(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();
Rect bounds = windowMetrics.getBounds();
Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility(
WindowInsets.Type.systemBars()
);
if (activity.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE
&& activity.getResources().getConfiguration().smallestScreenWidthDp < 600
) { // landscape and phone
return bounds.height();
} else { // portrait or tablet
int navigationBarSize = insets.bottom;
return bounds.height() - navigationBarSize;
}
} else {
DisplayMetrics outMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
}
The points are
- SystemBar's height is not included in Window bound's height. We should exclude NavigationBar's height only (unless it is in landscape mode on phone device).
- In landscape mode on phone device, we should exclude NavigationBar's size from Window bound's width.
TESTS
1. On my real phone (API-30)
portrait:
2021-12-14 22:17:28.231 31660-31660/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (1080, 2016)
2021-12-14 22:17:28.237 31660-31660/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (1080, 2016)
landscape:
2021-12-14 22:17:35.858 31660-31660/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (2016, 1080)
2021-12-14 22:17:35.887 31660-31660/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (2016, 1080)
2. On emulated Nexus10 (API-31)
portrait:
2021-12-14 22:19:33.379 1416-1416/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (1600, 2464)
2021-12-14 22:19:33.382 1416-1416/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (1600, 2464)
lanscape:
2021-12-14 22:18:44.809 1416-1416/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (2560, 1504)
2021-12-14 22:18:44.814 1416-1416/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (2560, 1504)
2. On emulated Nexus7 (API-31)
portrait:
2021-12-14 22:21:21.606 3108-3108/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (800, 1216)
2021-12-14 22:21:21.610 3108-3108/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (800, 1216)
landscape:
2021-12-14 22:22:23.283 3108-3108/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (1280, 736)
2021-12-14 22:22:23.289 3108-3108/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (1280, 736)
Solution 4:[4]
val windowMetrics = requireActivity().windowManager.currentWindowMetrics
val displayMetrics = resources.displayMetrics
val pxHeight = windowMetrics.bounds.height()
val pxWidth = windowMetrics.bounds.width()
val density = displayMetrics.density
val dpHeight = pxHeight/density
val dpWidth = pxWidth/density
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ryan M |
| Solution 2 | Community |
| Solution 3 | |
| Solution 4 | Muhammed naseef Koppilakkal |
