在 API 级别 30 (Android 11) 上获取屏幕宽度:现在不推荐使用 getDefaultDisplay() 和 getMetrics()。我们应该用什么来代替?

Den*_*nis 20 android deprecated deprecation-warning

我目前计算屏幕宽度是这样的:

public static int getScreenWidth(@NonNull Context context) {
    DisplayMetrics displayMetrics = new DisplayMetrics();
    ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    return displayMetrics.widthPixels;
}
Run Code Online (Sandbox Code Playgroud)

由于这两个函数(getDefaultDisplay()getMetrics())现在已被弃用,我们应该改用什么?

Rya*_*ley 33

为了计算屏幕宽度减去任何系统栏,这应该有效:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这并不完全相同:使用高度进行测试会产生不同的结果,而且我无法使用新 API 复制旧 API 的功能(部分原因是旧 API 的行为有点棘手)原因并不总是你想要的,因此它被弃用)。但在实践中,它应该足以作为许多事情的通用屏幕宽度。

  • 我想我们还应该使用`window.decorView.rootWindowInsets?.displayCutout`(`safeInsetLeft`和`safeInsetRight`),那些不都是`0`,有些> 0 (3认同)
  • 和 R+ 的密度? (3认同)
  • 我正在阅读文档,我也认为应该这样做。你是对的。 (2认同)
  • 使用windowMetrics.getWindowInsets()时有一个问题,当屏幕强制从纵向旋转到横向时,Insets.left和insets.right返回始终为0。 (2认同)

dra*_*onx 17

在 2022 年遇到同样的问题,有一个新的 Jetpack 库可以跨各种 API 版本处理这个问题。

构建.gradle

dependencies {
    implementation 'androidx.window:window:1.0.0'

}
Run Code Online (Sandbox Code Playgroud)
import androidx.window.layout.WindowMetrics;
import androidx.window.layout.WindowMetricsCalculator;


WindowMetrics windowMetrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(activity);
final int height = windowMetrics.getBounds().height();
final int width = windowMetrics.getBounds().width();
Run Code Online (Sandbox Code Playgroud)

我还遇到的一个警告是,includeandroidx.window最终引入了数以万计的库方法,这些方法使我超出了 DEX 64k 方法的限制,因此我必须弄清楚如何使用 R8/proguard 设置来优化这些方法,但这是另一个问题问题。


Vin*_*gas 6

@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
        }
    }
Run Code Online (Sandbox Code Playgroud)

这需要androidx.core版本1.5.x

  • 你的 RequiresApi 是错误的,它需要 API 级别 23。 (3认同)

hat*_*ata 5

我想我已经成功实现了与已弃用的方法等效的方法(改进@RyanM's)。

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

要点是

  1. SystemBar 的高度不包含在 Window 边界的高度中。我们应该仅排除导航栏的高度(除非它在手机设备上处于横向模式)。
  2. 在手机设备的横向模式下,我们应该从窗口边界的宽度中排除导航栏的大小。

测试

1. 在我的真实手机上(API-30)

肖像:

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)
Run Code Online (Sandbox Code Playgroud)

景观:

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)
Run Code Online (Sandbox Code Playgroud)

2. 在模拟的 Nexus10 (API-31) 上

肖像:

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)
Run Code Online (Sandbox Code Playgroud)

景观:

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)
Run Code Online (Sandbox Code Playgroud)

2. 在模拟的 Nexus7 (API-31) 上

肖像:

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)
Run Code Online (Sandbox Code Playgroud)

景观:

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)
Run Code Online (Sandbox Code Playgroud)