安卓canvas path addArc()与arcTo()方法的区别

在学习自定义view的时候,跟随https://hencoder.com/ui-1-1/的教程写写demo,遇到一个问题,需求是这样的,使用canvas的drawPath()方法绘制一个心形,如下图

安卓canvas path addArc()与arcTo()方法的区别_第1张图片 需要绘制一个心形
​​​
​​​​​​

教程给的代码是

public class PathView extends View {

    Paint paint = new Paint();
    Path path = new Path(); // 初始化 Path 对象
    
    ......
    
    {
      // 使用 path 对图形进行描述(这段描述代码不必看懂)
      path.addArc(200, 200, 400, 400, -225, 225);
      path.arcTo(400, 200, 600, 400, -180, 225, false);
      path.lineTo(400, 542);
    }

    @Override
    protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);
      
      canvas.drawPath(path, paint); // 绘制出 path 描述的图形(心形),大功告成
    }
}

后来自己尝试实现的时候,把图形分解了一下,如图

安卓canvas path addArc()与arcTo()方法的区别_第2张图片

于是,很自然的按照这个步骤来绘制图形,首先 添加左边的弧

path.addArc(100,100,300,300,-225,225);

其次,添加右边的弧

path.addArc(300,100,500,300,180,225);

最后,连接到中间点

path.lineTo(300,450);

开始运行! 

安卓canvas path addArc()与arcTo()方法的区别_第3张图片

???

安卓canvas path addArc()与arcTo()方法的区别_第4张图片

 

为什么会这样呢,lineTo不是会把图形没封闭的地方连接起来吗,怎么左边不连呢?

找了一会,发现跟源代码不一样的地方就是第二个弧形的绘制,我用了addArc() 方法,而源代码用的是arcTo()方法,问题肯定在这里,接下来就是找这两个方法的区别了,作者大佬对这两个方法有着如下解释:

 

另外,第二组还有两个特殊的方法: arcTo() 和 addArc()。它们也是用来画线的,但并不使用当前位置作为弧线的起点。

arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(RectF oval, float startAngle, float sweepAngle) 画弧形

这个方法和 Canvas.drawArc() 比起来,少了一个参数 useCenter,而多了一个参数 forceMoveTo 。

少了 useCenter ,是因为 arcTo() 只用来画弧形而不画扇形,所以不再需要 useCenter 参数;而多出来的这个 forceMoveTo 参数的意思是,绘制是要「抬一下笔移动过去」,还是「直接拖着笔过去」,区别在于是否留下移动的痕迹

paint.setStyle(Style.STROKE);
path.lineTo(100, 100);
path.arcTo(100, 100, 300, 300, -90, 90, true); // 强制移动到弧形起点(无痕迹)

安卓canvas path addArc()与arcTo()方法的区别_第5张图片

paint.setStyle(Style.STROKE);
path.lineTo(100, 100);
path.arcTo(100, 100, 300, 300, -90, 90, false); // 直接连线连到弧形起点(有痕迹)

安卓canvas path addArc()与arcTo()方法的区别_第6张图片

addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle) / addArc(RectF oval, float startAngle, float sweepAngle)

又是一个弧形的方法。一个叫 arcTo ,一个叫 addArc(),都是弧形,区别在哪里?其实很简单: addArc() 只是一个直接使用了 forceMoveTo = true 的简化版 arcTo() 。

paint.setStyle(Style.STROKE);
path.lineTo(100, 100);
path.addArc(100, 100, 300, 300, -90, 90);

安卓canvas path addArc()与arcTo()方法的区别_第7张图片

 

 按这个理解,使用arcTo()方法,forceMoveTo参数值为true的时候,相当于直接将笔提起来,从另一个点开始绘制第二段弧,虽然这一段弧的起点与第一段弧有重叠的部分,但是,在计算机看来,这跟之前的弧形已经是不封闭的另一个图形了,因此,在接下来使用lineTo()方法将图形封闭的时候,封闭的只是第二段弧与中心点组成的图形,也就形成了我上面出现的不完整心形图案

为了证实上面的结论,我将第二段弧形的起始位置故意往右偏移了一小段,使它不与第一段弧相交,得到的图案如下:

 path.addArc(100,100,300,300,-225,225);
 path.arcTo(350,100,500,300,180,225,true);

安卓canvas path addArc()与arcTo()方法的区别_第8张图片 

 

可以看到,当forceMoveTo参数值为true时,整个图形其实是分成了两个封闭图形,之前由于两个图形相交,视觉上看不出来。

把forceMoveTo的值改为false,使“笔迹”不断,这样的话所有的图形连在一起,是一段封闭图形

 path.addArc(100,100,300,300,-225,225);
 path.arcTo(350,100,500,300,180,225,false);

安卓canvas path addArc()与arcTo()方法的区别_第9张图片 

 

最后,总结一下这个事的结论,

addArc() 只是一个直接使用了 forceMoveTo = true 的简化版 arcTo()

forceMoveTo的值决定图案是否连续,也就间接决定了调用path.close()时,封闭图形的连接

 

2019年11月4日18:05:48
解答问题:arcTo方法的最后一个参数forceMoveTo的含义是“是否强制移动绘制点”,如果这个值为true,代表
强制移动了当前绘制点的位置,这样的话后续绘制的图形与之前绘制的图形是分隔开的,调用path.close()方法
的时候不会连接之前绘制的点了;这个值为false的时候,会将接下来的绘制点与之前的图形最后一个绘制点连接起来,
这样的话,之前绘制的图形与之后绘制的图形还是一个整体,调用path.close()方法的时候会将未封闭的图形连接起来。
addArc()方法本质上是一个forceMoveTo参数值为true的arcTo()方法

你可能感兴趣的:(安卓canvas path addArc()与arcTo()方法的区别)