近期在做项目的时候碰到了底部虚拟按键在各个厂商适配的问题,闷逼了一圈,后面搜索一圈,发现即使各大厂商有变动,还是离不开原生本质
我们都知道activity >> window >> decorView,适配的问题,闷逼了一圈,后面搜索一圈,发现即使各大厂商有变动,还是离不开原生本质
我们都知道activity >> window >> decorView,Window是视图的承载器,内部持有一个 DecorView,而这个DecorView才是 view 的根布局。Window是一个抽象类,实际在Activity中持有的是其子类PhoneWindow。
public class Activity extends ContextThemeWrappe{
private Window mWindow;
mWindow = new PhoneWindow(this);
}
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 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的关系了,就是他的两个儿子。
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;
}
}