背景
近期在做项目的时候碰到了底部虚拟按键在各个厂商适配的问题,闷逼了一圈,后面搜索一圈,发现即使各大厂商有变动,还是离不开原生本质
正题
我们都知道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; }
}