fitsSystemWindows 介绍
根据官方文档,如果某个View 的fitsSystemWindows 设为true,那么该View的padding属性将由系统设置,用户在布局文件中设置的
padding会被忽略。系统会为该View设置一个paddingTop,值为statusbar的高度。fitsSystemWindows默认为false。
重要说明:
- 只有将statusbar设为透明,或者界面设为全屏显示(设置View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flag)时,fitsSystemWindows才会起作用。不然statusbar的空间轮不到用户处理,这时会由ContentView的父控件处理,如果用HierarchyView 工具查看,将会看到,ContentView的父控件的paddingTop将会被设置。
- 如果多个view同时设置了fitsSystemWindows,只有第一个会起作用。这是一般情况,后面会介绍特殊情况。
fitsSystemWindows属性的个性化
第一次接触fitsSystemWindows是在CoordinatorLayout控件。发现有很多诡异的地方。
- fitsSystemWindows的表现和官方文档描述的不一样。
- 有时CoordinatorLayout的子控件也会设置fitsSystemWindows属性,而且子控件的fitsSystemWindows也会有作用。
这些令我很困惑,查了些资料之后找到了原因:设置paddingTop只是fitsSystemWindows属性的默认行为,View可以对fitsSystemWindows
进行个性化。fuccccccccccccccck!!!!!!!!!
CoordinatorLayout对fitsSystemWindows的个性化。API 21 以上可以通过调用View的setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener)函数,改变fitsSystemWindows的默认行为。在OnApplyWindowInsetsListener的onApplyWindowInsets函数,可以决定如何处理statusbar的空间。
重要说明:
- 在API 21以前,好像也可以重写View的某个函数达到类似效果。
- 必须将statusbar设为透明,或者界面设为全屏显示setOnApplyWindowInsetsListener才会起作用。这点很容易理解,你都没有statusbar空间,你个性化个屁啊。
CoordinatorLayout对fitsSystemWindows的个性化,关键代码:
if (ViewCompat.getFitsSystemWindows(view)) {
// First apply the insets listener
ViewCompat.setOnApplyWindowInsetsListener(view, insetsListener);
// Now set the sys ui flags to enable us to lay out in the window insets
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
final class ApplyInsetsListener implements android.support.v4.view.OnApplyWindowInsetsListener {
@Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
setWindowInsets(insets);
return insets.consumeSystemWindowInsets();
}
}
总结:CoordinatorLayout对fitsSystemWindows主要做了以下处理。
- 将界面设为全屏。view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- 自己绘制statusbar背景。setStatusBarBackground函数可以设置statusbar背景。或者在布局文件中通过app:statusBarBackground设置。
- 如果CoordinatorLayout的子View没有设置fitsSystemWindows,在layout时将子Viwe向下偏移statusbar的高度,用来显示CoordinatorLayout绘制的statusbar。如果子view设置了fitsSystemWindows,子View会覆盖CoordinatorLayout的statusbar。setStatusBarBackground设置的状态栏
将被覆盖,不再起作用。具体逻辑可参考CoordinatorLayout的layoutChild 函数。 - 调用dispatchApplyWindowInsets,让子view的behavior或子view接着处理fitsSystemWindows属性。CoordinatorLayout的很多常用的子view如AppBarLayout也对fitsSystemWindows进行了个性化处理。