Android控件的fitSystemWindows属性

官方描述:bash

根据系统窗体里的元素好比状态栏来调整View的布局。若是被设为true,控件的padding将会被调整为顶部留出一个statusBar的空间。相似于伪代码paddingTop="statusBarHeight"。ide

重点说明布局

  1. 当布局内容能够延伸到状态栏,被状态栏覆盖时(好比设置了View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,默认不会有这个flag,布局不会延伸到状态栏下),该属性才会起做用
  2. 静态布局中多个View的fitSystemWindows都为true,只对最外层(如同层,则为第一个)的View起做用
  3. 动态添加子View过程当中,只会对第一次添加的子View起做用

上述二、3点和官方描述的行为都是默认行为,而这个行为能够经过自定义View来进行个性化,好比CoordinateLayout就重载了这种行为(能够参考下方连接文章)ui

多Fragment时fitSystemWindows无效的坑

最近一个项目中,有几个界面是一个Activity装载多个Fragment的形式,为了实现沉浸式布局,将Activity的decorView加上View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN(使布局延伸到状态栏),全部Fragment的布局中,则将在最顶部的View(好比Toolbar)的fitSystemWindows设为true。 却惊讶地发现,只有第一个被加入到Activity的Fragment显示正常,随后被添加的Fragment都适配错误,以下图:this

缘由spa

添加Fragment的过程可看做往容器布局添加子View的过程。当第一个Fragment被添加到容器布局时,容器布局找出fitSystemWindows为true的子View,并为其paddingTop一个状态栏的高度,当其余Fragment随后被添加时,上述的paddingTop适配已经被消费过一次,并不会再为其后添加的View进行适配(默认行为),所以咱们要自定义容器布局View,使其每一个子View都消费一次ViewGroup分发的WindowsInsets,至关于每一个子Fragment都能适配状态栏.net

注意code

此方法实现的布局容器会对其每一个子View都适配一次cdn

实现代码blog

我通常用FrameLayout做为容器布局,所以继承了FrameLayout,每次addView都requestApplyInsets请求分发WindowInsets,而且保存当前添加的子View,在重载方法onApplyWindowInsets中调用子View的dispatchApplyWindowInsets,使每一个子View都有机会消费一次insets

class WindowInsetsFrameLayout: FrameLayout {

    private var requestView: View? = null

    constructor(context: Context): this(context, null)
    constructor(context: Context, attrs: AttributeSet?): this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) {
        setOnHierarchyChangeListener(object : OnHierarchyChangeListener {
            override fun onChildViewAdded(parent: View?, child: View?) {
                requestView = child
                requestApplyInsets() //子View添加时申请解析inset
            }

            override fun onChildViewRemoved(parent: View?, child: View?) {}
        })
    }

    override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets? {
        val t = requestView
        return if (t == null) {
            super.onApplyWindowInsets(insets)
        } else {
            val res = t.dispatchApplyWindowInsets(insets) //子View解析
            requestView = null
            res
        }
    }
}
复制代码

参考连接

www.twblogs.net/a/5cc8d540b…

www.jianshu.com/p/7bbce110a…

相关文章
相关标签/搜索