在 API 级别 30 (Android 11) 上获取屏幕宽度:getDefaultDisplay() 和 getMetrics() 现在已弃用。我们应该用什么代替?
Getting screen width on API Level 30 (Android 11): getDefaultDisplay() and getMetrics() are now deprecated. What should we use instead?
我目前是这样计算屏幕宽度的:
public static int getScreenWidth(@NonNull Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
由于这 2 个函数(getDefaultDisplay() 和 getMetrics())现已弃用,我们应该使用什么来代替?
要计算屏幕宽度减去任何系统栏,这应该有效:
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;
}
}
请注意,这完全不一样:用高度测试它会产生不同的结果,我无法复制旧的API' s 与新 API 的功能(部分原因是旧 API 的行为有点难以推理,而且并不总是你想要的,因此它被弃用了)。但在实践中,对于很多事情来说,它作为通用屏幕宽度应该足够好。
您可以使用
Context.getDisplay()
而不是 getDefaultDisplay()
display.getRealMatrix(displayMetrics)
而不是 display.getMetrics(displayMetrics)
@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
}
}
这需要 androidx.core
版本 1.5.x
我想我已经成功地实现了与弃用方法等效的方法(改进 )。
@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;
}
}
积分是
- SystemBar 的高度不包含在Window 边界的高度中。我们应该只排除 NavigationBar 的高度(除非它在 phone 设备上处于横向模式)。
- 在 phone 设备的横向模式下,我们应该从 Window 边界的宽度中排除 NavigationBar 的大小。
测试
1.在我真实的 phone (API-30)
纵向:
2021-12-14 22:17:28.231 31660-31660/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (1080, 2016)
2021-12-14 22:17:28.237 31660-31660/com.Whosebug.windowmetrics D/API-30+: (width, height) = (1080, 2016)
横向:
2021-12-14 22:17:35.858 31660-31660/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (2016, 1080)
2021-12-14 22:17:35.887 31660-31660/com.Whosebug.windowmetrics D/API-30+: (width, height) = (2016, 1080)
2。在模拟 Nexus10 (API-31)
纵向:
2021-12-14 22:19:33.379 1416-1416/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (1600, 2464)
2021-12-14 22:19:33.382 1416-1416/com.Whosebug.windowmetrics D/API-30+: (width, height) = (1600, 2464)
横向:
2021-12-14 22:18:44.809 1416-1416/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (2560, 1504)
2021-12-14 22:18:44.814 1416-1416/com.Whosebug.windowmetrics D/API-30+: (width, height) = (2560, 1504)
2。在模拟 Nexus7 (API-31)
纵向:
2021-12-14 22:21:21.606 3108-3108/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (800, 1216)
2021-12-14 22:21:21.610 3108-3108/com.Whosebug.windowmetrics D/API-30+: (width, height) = (800, 1216)
横向:
2021-12-14 22:22:23.283 3108-3108/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (1280, 736)
2021-12-14 22:22:23.289 3108-3108/com.Whosebug.windowmetrics D/API-30+: (width, height) = (1280, 736)
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
我目前是这样计算屏幕宽度的:
public static int getScreenWidth(@NonNull Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
由于这 2 个函数(getDefaultDisplay() 和 getMetrics())现已弃用,我们应该使用什么来代替?
要计算屏幕宽度减去任何系统栏,这应该有效:
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;
}
}
请注意,这完全不一样:用高度测试它会产生不同的结果,我无法复制旧的API' s 与新 API 的功能(部分原因是旧 API 的行为有点难以推理,而且并不总是你想要的,因此它被弃用了)。但在实践中,对于很多事情来说,它作为通用屏幕宽度应该足够好。
您可以使用
Context.getDisplay()
而不是 getDefaultDisplay()
display.getRealMatrix(displayMetrics)
而不是 display.getMetrics(displayMetrics)
@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
}
}
这需要 androidx.core
版本 1.5.x
我想我已经成功地实现了与弃用方法等效的方法(改进
@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;
}
}
积分是
- SystemBar 的高度不包含在Window 边界的高度中。我们应该只排除 NavigationBar 的高度(除非它在 phone 设备上处于横向模式)。
- 在 phone 设备的横向模式下,我们应该从 Window 边界的宽度中排除 NavigationBar 的大小。
测试
1.在我真实的 phone (API-30)
纵向:
2021-12-14 22:17:28.231 31660-31660/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (1080, 2016)
2021-12-14 22:17:28.237 31660-31660/com.Whosebug.windowmetrics D/API-30+: (width, height) = (1080, 2016)
横向:
2021-12-14 22:17:35.858 31660-31660/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (2016, 1080)
2021-12-14 22:17:35.887 31660-31660/com.Whosebug.windowmetrics D/API-30+: (width, height) = (2016, 1080)
2。在模拟 Nexus10 (API-31)
纵向:
2021-12-14 22:19:33.379 1416-1416/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (1600, 2464)
2021-12-14 22:19:33.382 1416-1416/com.Whosebug.windowmetrics D/API-30+: (width, height) = (1600, 2464)
横向:
2021-12-14 22:18:44.809 1416-1416/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (2560, 1504)
2021-12-14 22:18:44.814 1416-1416/com.Whosebug.windowmetrics D/API-30+: (width, height) = (2560, 1504)
2。在模拟 Nexus7 (API-31)
纵向:
2021-12-14 22:21:21.606 3108-3108/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (800, 1216)
2021-12-14 22:21:21.610 3108-3108/com.Whosebug.windowmetrics D/API-30+: (width, height) = (800, 1216)
横向:
2021-12-14 22:22:23.283 3108-3108/com.Whosebug.windowmetrics D/Upto API-29: (width, height) = (1280, 736)
2021-12-14 22:22:23.289 3108-3108/com.Whosebug.windowmetrics D/API-30+: (width, height) = (1280, 736)
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