原理查看:https://juejin.cn/post/6844903760007790600 根据传入的Beizer 曲线控制点来生成对应曲线上的点(n阶)
object Bezier {
const val X_TYPE = 1L
const val Y_TYPE = 2L
fun buildBezierPonit(
controlPointList: List<PointF>,
frame: Int
): MutableList<PointF> {
val pointList: MutableList<PointF> = ArrayList()
val delta = 1f / frame
val order = controlPointList.size - 1
var u = 0f
while (u <= 1) {
pointList.add(
PointF(
calculatePointCoordinate(X_TYPE, u, order, 0, controlPointList),
calculatePointCoordinate(Y_TYPE, u, order, 0, controlPointList)
)
)
u += delta
}
return pointList
}
fun calculatePointCoordinate(
@IntRange(from = X_TYPE, to = Y_TYPE)
type: Long,
u: Float,
k: Int,
p: Int,
controlPointList: List<PointF>
): Float {
return if (k == 1) {
val p1: Float
val p2: Float
if (type == X_TYPE) {
p1 = controlPointList[p].x
p2 = controlPointList[p + 1].x
} else {
p1 = controlPointList[p].y
p2 = controlPointList[p + 1].y
}
(1 - u) * p1 + u * p2
} else {
((1 - u) * calculatePointCoordinate(type, u, k - 1, p, controlPointList)
+ u * calculatePointCoordinate(type, u, k - 1, p + 1, controlPointList))
}
}
}
使用方式(示例中为6 阶Bezier 曲线):
class BezierView @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null
) : View(context, attributeSet) {
private val bezierPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val bezierPath = Path()
private val bezierControlPointList = arrayListOf<PointF>(
PointF(0f, 0f),
PointF(300f, 0f),
PointF(400f, 400f),
PointF(600f, 0f),
PointF(700f, 0f),
PointF(1000f, 345f),
PointF(435f, 500f),
)
init {
bezierPaint.apply {
style = Paint.Style.STROKE
strokeWidth = 4f
color = Color.RED
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
Bezier.buildBezierPonit(bezierControlPointList, 1000).forEach {
Log.d(BezierView::class.java.simpleName, "onDraw: $it")
if (bezierControlPointList.indexOf(it) == 0) {
bezierPath.moveTo(it.x, it.y)
} else {
bezierPath.lineTo(it.x, it.y)
}
}
canvas.drawPath(bezierPath, bezierPaint)
}
}
效果图:
|