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…

相關文章
相關標籤/搜索