我刚刚解决了同样的问题,虽然使用的是RadialGradient
。
如果你想在每次绘制调用时更新着色器的位置数据,你应该预分配着色器(如提示所示),并且还应该预分配一个Matrix
。着色器实例仅公开getLocalMatrix
和setLocalMatrix
功能。
要做到这一点,您将使用setLocalMatrix
,传入一个Matrix
实例,并对其执行一些适当的变换。在您的情况下,我认为一个简单的平移变换就可以解决问题。
正如我之前提到的,您需要预分配一个Matrix
,并在每个绘制循环中修改此预分配的矩阵,然后将其传递到shader.setLocalMatrix
中。
以下是我如何更新RadialGradient
着色器的centerX
和centerY
的示例。这种用例是用户可以拖动圆形,我需要使径向渐变保持在圆形的中心。
下面的代码显示了一个完整的工作解决方案,作为自定义视图,您可以将其复制并粘贴到您的代码库中,并在某些XML中使用。
有趣的部分在于onDraw
覆盖,我正在进行矩阵变换并更新着色器:
class MoveableGradientCircle @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private data class Circle(
val radius: Float,
val centerX: Float,
val centerY: Float,
val paint: Paint,
val shaderMatrix: Matrix
)
private var circle: Circle = Circle(
radius = 10f,
centerX = x,
centerY = y,
paint = Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL_AND_STROKE
shader = RadialGradient(
centerX = 0f,
centerY = 0f,
radius = 10f,
startColor = Color.RED,
edgeColor = Color.GREEN,
tileMode = Shader.TileMode.CLAMP
)
},
shaderMatrix = Matrix()
)
init {
setOnTouchListener { view, event ->
view.performClick()
when (event.action) {
MotionEvent.ACTION_DOWN -> {
circle = circle.copy(
centerX = event.x,
centerY = event.y
)
invalidate()
true
}
MotionEvent.ACTION_MOVE -> {
circle = circle.copy(
centerX = event.x,
centerY = event.y
)
invalidate()
true
}
MotionEvent.ACTION_UP -> {
circle = circle.copy(
centerX = event.x,
centerY = event.y
)
invalidate()
true
}
else -> false
}
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
circle.shaderMatrix.reset()
circle.shaderMatrix.setTranslate(
circle.centerX,
circle.centerY
)
circle.paint.shader.setLocalMatrix(circle.shaderMatrix)
canvas?.drawArc(
circle.centerX - circle.radius,
circle.centerY - circle.radius,
circle.centerX + circle.radius,
circle.centerY + circle.radius,
0f,
360f,
true,
circle.paint
)
}
}
我希望这能帮助你或未来遇到同样问题的人!