Android绘图篇之Path(三)

316 阅读2分钟

Path

方法介绍

  • computeBounds(RectF, Boolean)
    • 计算Path边界,结果存在RectF中,第二个参数是否精确获取
fun computeBounds(Path path): RectF {
    val rectF = RectF()
    path.computeBounds(rectF, true)
    return rectF
}

// 相对精确
fun computeBounds(Path path): RectF {
    val rectF = RectF()
    path.computeBounds(rectF, true)
    val figureLocation = Rect(floor(rectF.left).toInt(), floor(rectF.top).toInt() , ceil(rectF.right).toInt(), ceil(rectF.bottom).toInt())
    val bounds = Rect()
    val region = Region()
    region.setPath(path, new Region(figureLocation)); region.getBounds(bounds)
    return RectF(bounds)
}
  • Path.addPath优于Path.addRoundRect

两条Path是否有交集

fun checkInterEraser(Path path1, Path path2): Boolean {
    val wh = ResTool.windowWH()
    Region clip = new Region(0, 0, wh[0], wh[1])
    Region eRegion = new Region()
    eRegion.setPath(path1, clip)
    Region sRegion = new Region()
    sRegion.setPath(path, clip)
    if (!eRegion.quickReject(sRegion) && eRegion.op(sRegion, Region.Op.INTERSECT)) {  
        return true
    }  
    return false
}  
  
fun getPath(points: List<Point>): Path {
    if (points.isNullOrEmpty()) {
        return null
    }  
    final int size = points.size()
    Path tempPath = new Path()
    tempPath.moveTo(points.get(0).x, points.get(0).y)

    PointF preP
    PointF curP
    for (int index = 0; index < size - 1; index++) {  
        preP = points.get(index)
        curP = points.get(index + 1)
        tempPath.quadTo(preP.x, preP.y, (preP.x + curP.x) / 2, (preP.y + curP.y) / 2)
    }  
    return tempPath
}  

PathMeasure实现路径动画

  • PathMeasure可计算出指定路径信息:路径总长度、指定长度对应坐标
// 方式一  
val pathMeasure = PathMeasure()  
val path = Path()  
// forceClosed:true,强制闭合计算终点到起点的距离,forceClosed仅对测量有影响,不会影响关联的path  
pathMeasure.setPath(path, true)  
  
// 方式二  
val path = Path()  
val pathMeasure = PathMeasure(path, true)  
  • 常用方法
// 获取路径长度:forceClosed:true强制闭合,true > false  
fun getLength(): Float  
  
// 是否闭合  
fun isClosed(): Boolean  
  
// path由多条曲线构成(addXxx()),用于跳转下一个线段,true:跳转成功  
fun nextContour(): Boolean  
  
// 线段截取:[startD, stopD] in [0, pathLength],截取线段添加至dst  
// startWithMoveTo:true新线段移动至dst起点,false新线段移动至dst终点(上一线段终点)  
// 注意:使用该方法需禁用硬件加速setLayerType(View.LAYER_TYPE_SOFTWARE, null)  
fun getSegment(startD: Float, stopD: Float, dst: Path, startWithMoveTo: Boolean)  
  • 路径实现加载动画
package com.dcxing.draw.tool
  
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PathMeasure

object ProgressTool {
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.BLUE
        style = Paint.Style.STROKE
        strokeCap = Paint.Cap.ROUND
        strokeJoin = Paint.Join.ROUND
        strokeWidth = 6f
    }

    private val circlePath = Path()
    private val dstPath = Path()
    private val pathMeasure = PathMeasure()
    var curAnimValue = 0f

    init {  
        circlePath.addCircle(90f, 90f, 45f, Path.Direction.CW)
        pathMeasure.setPath(circlePath, true)
    }  

    fun render(canvas: Canvas) {
        canvas.save()
        canvas.translate(300f, 0f)
        val length = pathMeasure.length
        val stop = length * curAnimValue
        val start =
            if (curAnimValue > 0.75f)
                (2 * curAnimValue - 1f) * length
            else if (curAnimValue > 0.25f)
                stop - 0.25f * length
            else
                0f
        dstPath.reset()
        pathMeasure.getSegment(start, stop, dstPath, true)
        canvas.drawPath(dstPath, paint)
        canvas.restore()
    }
}