美文网首页viewandroid状态栏和导航栏
令人困惑的fitsSystemWindows属性

令人困惑的fitsSystemWindows属性

作者: flaming | 来源:发表于2016-10-20 15:05 被阅读10982次

    fitsSystemWindows 介绍

    根据官方文档,如果某个View 的fitsSystemWindows 设为true,那么该View的padding属性将由系统设置,用户在布局文件中设置的
    padding会被忽略。系统会为该View设置一个paddingTop,值为statusbar的高度。fitsSystemWindows默认为false。

    重要说明:

    1. 只有将statusbar设为透明,或者界面设为全屏显示(设置View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flag)时,fitsSystemWindows才会起作用。不然statusbar的空间轮不到用户处理,这时会由ContentView的父控件处理,如果用HierarchyView 工具查看,将会看到,ContentView的父控件的paddingTop将会被设置。
    2. 如果多个view同时设置了fitsSystemWindows,只有第一个会起作用。这是一般情况,后面会介绍特殊情况。

    fitsSystemWindows属性的个性化

    第一次接触fitsSystemWindows是在CoordinatorLayout控件。发现有很多诡异的地方。

    1. fitsSystemWindows的表现和官方文档描述的不一样。
    2. 有时CoordinatorLayout的子控件也会设置fitsSystemWindows属性,而且子控件的fitsSystemWindows也会有作用。

    这些令我很困惑,查了些资料之后找到了原因:设置paddingTop只是fitsSystemWindows属性的默认行为,View可以对fitsSystemWindows
    进行个性化。fuccccccccccccccck!!!!!!!!!

    CoordinatorLayout对fitsSystemWindows的个性化。API 21 以上可以通过调用View的setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener)函数,改变fitsSystemWindows的默认行为。在OnApplyWindowInsetsListener的onApplyWindowInsets函数,可以决定如何处理statusbar的空间。
    重要说明:

    1. 在API 21以前,好像也可以重写View的某个函数达到类似效果。
    2. 必须将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主要做了以下处理。

    1. 将界面设为全屏。view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
    2. 自己绘制statusbar背景。setStatusBarBackground函数可以设置statusbar背景。或者在布局文件中通过app:statusBarBackground设置。
    3. 如果CoordinatorLayout的子View没有设置fitsSystemWindows,在layout时将子Viwe向下偏移statusbar的高度,用来显示CoordinatorLayout绘制的statusbar。如果子view设置了fitsSystemWindows,子View会覆盖CoordinatorLayout的statusbar。setStatusBarBackground设置的状态栏
      将被覆盖,不再起作用。具体逻辑可参考CoordinatorLayout的layoutChild 函数。
    4. 调用dispatchApplyWindowInsets,让子view的behavior或子view接着处理fitsSystemWindows属性。CoordinatorLayout的很多常用的子view如AppBarLayout也对fitsSystemWindows进行了个性化处理。

    相关文章

      网友评论

      本文标题:令人困惑的fitsSystemWindows属性

      本文链接:https://www.haomeiwen.com/subject/sobfuttx.html