Android 通过DecorView计算statusBar、navigationBar的高度

背景

近期在做项目的时候碰到了底部虚拟按键在各个厂商适配的问题,闷逼了一圈,后面搜索一圈,发现即使各大厂商有变动,还是离不开原生本质

正题

我们都知道activity >> window >> decorView,适配的问题,闷逼了一圈,后面搜索一圈,发现即使各大厂商有变动,还是离不开原生本质

activity 的 decorview

我们都知道activity >> window >> decorView,Window是视图的承载器,内部持有一个 DecorView,而这个DecorView才是 view 的根布局。Window是一个抽象类,实际在Activity中持有的是其子类PhoneWindow。

  • Activity相关代码:
public class Activity extends ContextThemeWrappe{
  private Window mWindow;

  mWindow = new PhoneWindow(this);
}
  • PhoneWindow 相关代码:
public class PhoneWindow extends Window{
  // This is the top-level view of the window, containing the window decor.
  private DecorView mDecor; 
}

DocorView包含了一个状态栏,一个navigationBar,一个LinearLayout我们通常的内容展示区,如下:


    
    

    

        
    

    

在这个LinearLayout里面有上下三个部分,上面是个ViewStub,延迟加载的视图(应该是设置ActionBar,根据Theme设置),中间的是标题栏(根据Theme设置,有的布局没有),下面的是内容栏。相关源码扯犊子到这边差不多,可以知道statusbar和navigationBar两者和decorView的关系了,就是他的两个儿子。

计算statusBar和NavigationBar的高度

public class DecorUtil {

    /**
     * 请勿在dialog中使用
     * 

* 主题的 android:windowTranslucentStatus 属性, 会影响 contentView 的 padding top. *

* 如果设置了 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN , 那么 contentView 的 padding top 都是 0 */ public static void demo(@NonNull final Window window) { final View decorView = window.getDecorView(); int measuredHeight = decorView.getMeasuredHeight(); if (measuredHeight <= 0) { decorView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { decorView.getViewTreeObserver().removeOnPreDrawListener(this); demo(window); return true; } }); } else { Rect outRect = new Rect(); decorView.getWindowVisibleDisplayFrame(outRect); L.w("可视区域:" + outRect); L.w("屏幕高度:" + measuredHeight); if (decorView instanceof ViewGroup) { int childCount = ((ViewGroup) decorView).getChildCount(); if (childCount > 0) { View contentView = ((ViewGroup) decorView).getChildAt(0); L.w("内容高度:" + contentView.getMeasuredHeight() + " p:" + contentView.getPaddingTop()); } if (childCount > 1) { View childView = ((ViewGroup) decorView).getChildAt(1); if (isStatusBar(decorView, childView)) { L.w("状态栏高度:" + childView.getMeasuredHeight()); } else if (isNavigationBar(decorView, childView)) { L.w("导航栏高度:" + childView.getMeasuredHeight()); } else { L.w("未知:" + childView); } } if (childCount > 2) { View childView = ((ViewGroup) decorView).getChildAt(2); if (isStatusBar(decorView, childView)) { L.w("状态栏高度:" + childView.getMeasuredHeight()); } else if (isNavigationBar(decorView, childView)) { L.w("导航栏高度:" + childView.getMeasuredHeight()); } else { L.w("未知:" + childView); } } } } } private static boolean isStatusBar(@NonNull View decorView, @NonNull View childView) { if (childView.getTop() == 0 && childView.getMeasuredWidth() == decorView.getMeasuredWidth() && childView.getBottom() < decorView.getBottom() ) { return true; } return false; } private static boolean isNavigationBar(@NonNull View decorView, @NonNull View childView) { if (childView.getTop() > decorView.getTop() && childView.getMeasuredWidth() == decorView.getMeasuredWidth() && childView.getBottom() == decorView.getBottom() ) { return true; } return false; } }

参考文献

https://blog.csdn.net/angcyo/article/details/53240763

你可能感兴趣的:(Android 通过DecorView计算statusBar、navigationBar的高度)