ValueAnimator修改非目标属性问题:为何未关联的RectF坐标会同步变化?
问题产生原因
- 隐式参数关联:你在
onDraw()、onLayout()或onSizeChanged()等绘制/测量回调中,计算bgCardBounds坐标时直接使用了动画控制的bitmapPadding作为计算因子。动画每更新一次bitmapPadding就会调用invalidate()触发重绘,重绘时会用最新的bitmapPadding重新计算bgCardBounds,导致其数值跟随动画同步变化,这是最高概率的诱因。 - 引用传递问题:RectF是引用类型,如果你在代码中存在
bgCardBounds = 其他和padding绑定的RectF这类直接赋值操作,两个变量会指向同一块内存地址,任意一个的数值修改都会同步到另一个上。 - 原生padding联动:如果你在自定义View中调用了原生的
setPadding()方法,且参数和bitmapPadding绑定,原生padding变化会触发View重排,进而影响onLayout()中bgCardBounds的赋值逻辑。
解决方案
- 针对隐式参数关联问题:将
bgCardBounds的计算逻辑从频繁调用的onDraw()中移至onSizeChanged(),仅在View尺寸变化时计算一次固定值,计算时使用独立于bitmapPadding的固定常量作为padding参数,避免每次重绘都同步动画值。
示例代码:
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) // 使用独立的固定padding计算bgCardBounds,不和动画控制的bitmapPadding关联 val fixedCardPadding = 16f bgCardBounds.set(fixedCardPadding, fixedCardPadding, w - fixedCardPadding, h - fixedCardPadding) } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) // 直接使用预计算好的bgCardBounds,不再重新赋值 canvas.drawRoundRect(bgCardBounds, 16f, 16f, bgPaint) // 绘制带padding动画的bitmap时单独使用bitmapPadding canvas.drawBitmap(targetBitmap, bitmapPadding, bitmapPadding, bitmapPaint) }
- 针对引用传递问题:不要对RectF对象直接使用
=赋值,改用set()方法做值拷贝,避免多个变量指向同一个对象。
错误写法示例:
// 错误:引用传递,修改tempRect会同步影响bgCardBounds val tempRect = RectF(bitmapPadding, bitmapPadding, 200f, 200f) bgCardBounds = tempRect
正确写法示例:
// 正确:值拷贝,两个RectF完全独立 val tempRect = RectF(bitmapPadding, bitmapPadding, 200f, 200f) bgCardBounds.set(tempRect)
- 针对原生padding联动问题:如果不需要修改View原生padding,不要调用
setPadding()方法,仅使用自定义的bitmapPadding变量控制绘制逻辑即可。
内容的提问来源于stack exchange,提问作者Nishant Jalan
相关产品推荐
相关产品推荐

