记录一个谷歌的坑,多Fragment中fitsSystemWindows只有第一个Fragment生效

第一个坑,多Fragment嵌套ViewPager2,偶尔会奔溃,报错信息

解决办法

viewPager2.isSaveEnabled = false
复制代码

但是你可能发现切换界面每次会重新创建一个fragment

解决办法

// 把 beginTransaction.replace 替换成 hide show
val beginTransaction = fragmentManager.beginTransaction()
    var hasFragment = false
    fragmentManager.fragments.forEach {
        it?.let {
            beginTransaction.hide(it)
            if(it == fragment){
                hasFragment = true
            }
        }
    }
    if(!hasFragment){
        beginTransaction.add(containerViewId,fragment,tag)
    }else{
        beginTransaction.show(fragment)
    }
复制代码

然后如果你的多个fragment 中fitsSystemWindows不一致,也就是说有的是true ,有的是false,别问我为什么这样,设计如此

查源码,当第一个Fragment添加到Activity中的时候,Activity寻找出有fitsSystemWindows的子布局为其预留出状态栏的空间,其实就是设置一个padding,而其他Fragment添加到Activity中的时候,因为状态栏空间的适配已经被消费过一次了,Activity并不会再次去添加这个padding。因此我们需要自定义一个FrameLayout,重写它的状态栏空间适配的时机和它的适配事件的分发 ,所以我们重写FrameLayout,网上找的代码无效,自己研究了一下,要在测量前将fitSystemWindows值传递给子布局,代码如下

import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.Context
import android.graphics.Rect
import android.os.Build
import android.util.AttributeSet
import android.view.WindowInsets
import android.widget.FrameLayout
import androidx.core.util.ObjectsCompat

/**
 * description:谷歌bug,重写FrameLayout,在测量前将fitSystemWindows值传递给子布局
 * version: 1.0
 */
class WindowInsetsFrameLayout : FrameLayout {
    private var mLastInsets: Any? = null

    constructor(context: Context?) : super(context!!)
    constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
        context!!,
        attrs,
        defStyle
    )

    @TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
    override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
        if (!ObjectsCompat.equals(mLastInsets, insets)) {
            mLastInsets = insets
            requestLayout()
        }
        return insets.consumeSystemWindowInsets()
    }

    override fun fitSystemWindows(insets: Rect): Boolean {
        if (!ObjectsCompat.equals(mLastInsets, insets)) {
            if (mLastInsets == null) {
                mLastInsets = Rect(insets)
            } else {
                (mLastInsets as Rect).set(insets)
            }
            requestLayout()
        }
        return true
    }

    @SuppressLint("DrawAllocation")
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        if (mLastInsets != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
                val wi = mLastInsets as WindowInsets
                val childCount = childCount
                for (i in 0 until childCount) {
                    val child = getChildAt(i)
                    if (child.visibility != GONE) {
                        child.dispatchApplyWindowInsets(wi)
                    }
                }
            } else {
                super.fitSystemWindows(Rect(mLastInsets as Rect?))
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享