android system window,Android控件的fitSystemWindows属性

官方描述:

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

重点说明:

当布局内容可以延伸到状态栏,被状态栏覆盖时(比如设置了View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,默认不会有这个flag,布局不会延伸到状态栏下),该属性才会起作用

静态布局中多个View的fitSystemWindows都为true,只对最外层(如同层,则为第一个)的View起作用

动态添加子View过程中,只会对第一次添加的子View起作用

上述2、3点和官方描述的行为都是默认行为,而这个行为可以通过自定义View来进行个性化,比如CoordinateLayout就重载了这种行为(可以参考下方链接文章)

多Fragment时fitSystemWindows无效的坑

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

54c1795a0f748af7d0d6c2736ef0c207.png

原因

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

注意

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

实现代码

我一般用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

}

}

}

复制代码

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值