概述
在Android中的圖形繪制中,有個(gè)很有名的曲線,叫貝塞爾曲線,可以用來完成一系列非常順滑的線段動(dòng)畫變化操作,這篇文章就簡(jiǎn)單學(xué)習(xí)一下Android自帶的貝塞爾曲線的繪制方法。
貝塞爾曲線繪制原理
1.一階貝塞爾曲線
一階貝塞爾曲線繪制出來就是一段直線,公式如下

824232-20170330144601373-1257210437.png
繪制效果

824232-20170330142921733-15684048.gif
2.二階貝塞爾曲線
二階貝塞爾曲線在起點(diǎn)和終點(diǎn)之間多了一個(gè)控制點(diǎn)來完成貝塞爾曲線的繪制,公式如下

824232-20170330144747889-2087843436.png
繪制效果

824232-20170330143512014-2132882514.gif
3.三階貝塞爾曲線
三階貝塞爾曲線則在起點(diǎn)和終點(diǎn)外有兩個(gè)點(diǎn)來控制貝塞爾曲線的繪制,公式如下

824232-20170330144819139-1318405514.png
繪制流程如下

824232-20170330143748045-500194673.gif
Android自帶繪制貝塞爾曲線的API
Android的SDK主要有以下兩個(gè)方法用來繪制貝塞爾曲線
- 繪制二階貝塞爾曲線
rQuadTo()中的參數(shù)均為偏移量
// 二階貝塞爾曲線
public void quadTo(float x1, float y1, float x2, float y2)
public void rQuadTo(float dx1, float dy1, float dx2, float dy2)
- 繪制三階貝塞爾曲線
我們一般很少使用三階的,所以這里只做簡(jiǎn)單介紹
// 三階貝塞爾曲線
public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
public void rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
簡(jiǎn)單繪制
1.繪制一條二階貝塞爾曲線
核心代碼如下
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
var path = Path()
path.moveTo(100f,150f)
path.quadTo(200f,250f,300f,150f)
path.quadTo(400f,50f,500f,150f)
canvas?.drawPath(path,paint)
}
運(yùn)行結(jié)果

device-2021-09-07-212451.png
用貝塞爾曲線完成手指滑動(dòng)路徑捕捉
package com.tx.camera.view
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
/**
* create by xu.tian
* @date 2021/9/7
*/
class BezierView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
var paint : Paint = Paint()
init {
paint.style = Paint.Style.STROKE
paint.strokeWidth = 5f
paint.color = Color.WHITE
}
var preX = 0f
var preY = 0f
var path = Path()
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawPath(path,paint)
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event?.action){
MotionEvent.ACTION_DOWN -> actionDown(event)
// MotionEvent.ACTION_MOVE -> linePathMove(event)
MotionEvent.ACTION_MOVE -> bezierPathMove(event)
}
return true
}
private fun actionDown(event: MotionEvent){
preX = event.x
preY = event.y
path.moveTo(preX,preY)
}
// 傳統(tǒng)路徑捕捉
private fun linePathMove(event: MotionEvent){
path.lineTo(event.x,event.y)
postInvalidate()
}
// 利用貝塞爾曲線完成路徑捕捉
private fun bezierPathMove(event: MotionEvent){
path.quadTo(preX,preY,(event.x+preX)/2,(event.y+preY)/2)
preX = event.x
preY = event.y
postInvalidate()
}
}
運(yùn)行效果

bezier.gif
上述例子中將普通的lineTo()方式實(shí)現(xiàn)的路徑捕捉也寫進(jìn)去了,感興趣的同學(xué)可以對(duì)比一下兩者的差異,正常情況下貝塞爾實(shí)現(xiàn)的會(huì)更加順暢一點(diǎn)。
總結(jié)
今天就寫到這里了,下篇再接著寫自定義View的其他內(nèi)容~