Android 11+强制旋转屏幕后WindowInsets获取Insets左右值为0问题求解
问题根因
你遇到的insets值获取不准确问题,本质是调用getCurrentWindowMetrics的时机早于系统布局更新完成时间:强制旋转触发后,Activity的布局、WindowInsets计算需要一定时间,你在旋转代码执行后立刻读取的WindowMetrics还是旋转前的缓存值,所以左右边距不对。
你观测到的几个异常现象也符合这个逻辑:应用第二次启动时系统保留了上一次的Insets缓存,所以能拿到正确值;触碰主屏幕会清掉系统保存的应用Window状态缓存,重启后首次读取就会拿到旧值。
解决方案
方案1:监听WindowInsets回调(最可靠)
不要在Activity早期生命周期(onCreate/onStart)主动拉取Insets,而是给根布局注册OnApplyWindowInsetsListener,系统完成Insets计算后会主动回调,此时拿到的边距一定是当前最新值:
// 在Activity onCreate中调用 getWindow().getDecorView().setOnApplyWindowInsetsListener((v, windowInsets) -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { Insets insets = windowInsets.getInsetsIgnoringVisibility( WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout() ); // 此处获取的left、right为准确值,可直接保存使用 int leftInset = insets.left; int rightInset = insets.right; int usableWidth = v.getWidth() - leftInset - rightInset; int usableHeight = v.getHeight() - insets.top - insets.bottom; } return windowInsets; // 如果子布局需要用到Insets,不要消费,直接返回原对象 });
方案2:延迟到布局完成后主动获取
如果业务需要主动调用方法获取尺寸,把获取逻辑post到主线程消息队列末尾,等布局渲染完成后再执行:
// 执行强制横屏代码后 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); // 等待布局完成后再读取尺寸 getWindow().getDecorView().post(() -> { int currentWidth = getDisplaySize(getWindowManager(), true); // 此处拿到的是正确的宽高值 });
方案3:使用Jetpack WindowManager兼容库(推荐)
Google官方推出的WindowManager兼容库已经处理了不同版本、不同场景下的Insets获取逻辑,不需要自己做版本判断,稳定性更高:
- 先添加依赖:
// 模块级build.gradle中添加 implementation "androidx.window:window:1.2.0" - 直接获取最新的WindowMetrics:
WindowMetricsCalculator calculator = WindowMetricsCalculator.getOrCreate(); WindowMetrics currentMetrics = calculator.computeCurrentWindowMetrics(this); WindowInsetsCompat insetsCompat = WindowInsetsCompat.toWindowInsetsCompat( currentMetrics.getWindowInsets() ); // 获取边距 Insets insets = insetsCompat.getInsets( WindowInsetsCompat.Type.navigationBars() | WindowInsetsCompat.Type.displayCutout() ); int leftInset = insets.left; int rightInset = insets.right; // 计算可用尺寸 Rect bounds = currentMetrics.getBounds(); int usableWidth = bounds.width() - leftInset - rightInset; int usableHeight = bounds.height() - insets.top - insets.bottom;
内容的提问来源于stack exchange,提问作者CodingBruceLee
相关产品推荐
相关产品推荐

