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
}
遇到的问题整理
- 对称布局提供了API直接在存在的LayoutParams对象上创建新实例,但是修改以后,原来的View也会被改变,和对Java的理解不一样
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的属性~