前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 通过DecorView计算statusBar、navigationBar的高度

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

作者头像
包子388321
发布2020-06-16 09:46:56
1.9K0
发布2020-06-16 09:46:56
举报
文章被收录于专栏:包子的书架

背景

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

正题

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

activity 的 decorview

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

  • Activity相关代码:
代码语言:javascript
复制
public class Activity extends ContextThemeWrappe{
  private Window mWindow;

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

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

代码语言:javascript
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <!-- Popout bar for action modes -->
    <ViewStub
        android:id="@+id/action_mode_bar_stub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inflatedId="@+id/action_mode_bar"
        android:layout="@layout/action_mode_bar"
        android:theme="?attr/actionBarTheme" />

    <FrameLayout
        style="?android:attr/windowTitleBackgroundStyle"
        android:layout_width="match_parent"
        android:layout_height="?android:attr/windowTitleSize">

        <TextView
            android:id="@android:id/title"
            style="?android:attr/windowTitleStyle"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@null"
            android:fadingEdge="horizontal"
            android:gravity="center_vertical" />
    </FrameLayout>

    <FrameLayout
        android:id="@android:id/content"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foreground="?android:attr/windowContentOverlay"
        android:foregroundGravity="fill_horizontal|top" />
</LinearLayout>

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

计算statusBar和NavigationBar的高度
代码语言:javascript
复制
public class DecorUtil {

    /**
     * 请勿在dialog中使用
     * <p>
     * 主题的 android:windowTranslucentStatus 属性, 会影响 contentView 的 padding top.
     * <p>
     * 如果设置了 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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 正题
    • activity 的 decorview
      • 计算statusBar和NavigationBar的高度
        • 参考文献
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档