Android自定義View(10) 《貝塞爾曲線簡(jiǎn)介》

概述

在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)容~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容