Android LayoutParams的深拷贝

2020-07-16  本文已影响0人  超级呆
  // 通用的复制属性方法
  private fun cloneParams(params: ViewGroup.LayoutParams): ViewGroup.LayoutParams {
        val paramsClass = params.javaClass
        val newInstance =
            Class.forName(paramsClass.name).getConstructor(ViewGroup.LayoutParams::class.java).newInstance(
                params
            ) as ViewGroup.LayoutParams
        for (paramsField in paramsClass.declaredFields) {
            if (TextUtils.equals(paramsField.name, "widget")) { // 该属性导致约束布局的后续修改,影响被复制的View属性
                   continue
            }
            paramsField.isAccessible = true
            paramsField.set(newInstance, paramsField.get(params))
            println("当前字段 ${paramsField.name}:${paramsField.get(params)}")
        }
        return newInstance
    }

遇到的问题整理

androidx.constraintlayout.widget.ConstraintLayout.LayoutParams#LayoutParams(androidx.constraintlayout.widget.ConstraintLayout.LayoutParams)

使用该API,理论上应该会深拷贝一个新的实例,修改该实例的值,不应该影响原来的View的属性,代码层面是没有修改,但是实际效果是修改了的。

目前还不清楚原因 …

原因排查:
androidx.constraintlayout.widget.ConstraintLayout.LayoutParams#widget ->
androidx.constraintlayout.solver.widgets.ConstraintWidget

猜测可能是复制了widget属性

虽然没有找到确定的证据,但从android.support.constraint.ConstraintLayout#setChildrenConstraints中可窥一二,猜测是该属性决定了子View,在父布局ConstraintLayout的一个重排机制,用于外部设置ConstraintSet去设置该属性。

image.png

真相大白,从ConstraintLayout的布局方法中来看的话,可知道宽高以及绘制的位置取决与 ConstraintWidget , 所以如果通过反射获取对应的引用,会导致修改到原View的属性~

上一篇下一篇

猜你喜欢

热点阅读