在 Android 中画一个尖角的心

Drawing a Heart with Sharp Corner in Android

下面的问题可能听起来有点愚蠢,但我想愚蠢是没有限制的,所以就这样吧。我在 Android 中使用 Canvas 画了一颗心,在画心时没有遇到任何问题,但我无法在交汇点使心尖锐。我的心像

代码:

            left_x_moveto = 200;
            left_y_moveto = 45;

            left_x1 = 197;
            left_y1 = -35;
            left_x2 = 60;
            left_y2 = 20;
            left_x3 = 193;
            left_y3 = 130;

            right_x_moveto = 200;
            right_y_moveto = 45;

            right_x1 = 197;
            right_y1 = -35;
            right_x2 = 345;
            right_y2 = 20;
            right_x3 = 193;
            right_y3 = 130;



           heart_outline_paint.setColor(getResources().getColor(R.color.heart_outline_color)); // Change the boundary color
        heart_outline_paint.setStrokeWidth(15);
        heart_outline_paint.setStyle(Paint.Style.STROKE);

        path.moveTo(left_x_moveto, left_y_moveto);
        path.cubicTo(left_x1, left_y1, left_x2, left_y2, left_x3, left_y3);

        path.moveTo(right_x_moveto, right_y_moveto);
        path.cubicTo(right_x1, right_y1, right_x2, right_y2, right_x3, right_y3);
        canvas.drawPath(path, heart_outline_paint);

到目前为止我尝试了什么:

  1. 减少或增加left_x_moveto,left_y_moveto的点数,反之亦然,但心已完全毁容,我找不到原因。

right_x_moveto = 198right_y_moveto = 45时,心的样子

我不确定为什么会这样。

  1. 减少 heart_outline_paint 的宽度会得到我想要的,但我希望 心的厚度 相同,所以减少 setStrokeWidth 不是一个选项。

简而言之,我希望两条曲线都相遇并合并,而不仅仅是相遇。 任何帮助都感激不尽。提前致谢。

发生的情况是线的粗细是在一侧绘制的,而不是在两侧绘制的。在真正的 MS 绘画时尚中:

(左边是正在发生的事情,右边是你想要的。黑色是线的实际位置,宽度为 1px,红色是 "padding",第 2、3 到第 15 个像素,heart_outline_paint.setStrokeWidth(15);)

要解决此问题,请尝试从右线的 x 减去线宽的一半,并将其添加到左线的 x。这样做会解决这个问题,而不是解决它

你需要执行几个这样的操作。

  1. 通过path.close()关闭路径。
  2. 您需要通过heart_outline_paint.setStrokeJoin(Paint.Join.MITER);
  3. 设置笔画连接

一个path只有连续绘制才能关闭。因此,我修改了代码,以便 path.close() 可以正确完成。下面是代码。

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    heart_outline_paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    heart_outline_paint.setStrokeJoin(Paint.Join.MITER);
    path = new Path();

    int left_x_moveto = 200;
    int left_y_moveto = 45;

    int left_x1 = 180;
    int left_y1 = -20;
    int left_x2 = 30;
    int left_y2 = 20;
    int left_x3 = 193;
    int left_y3 = 130;

    int right_x_moveto = 200;
    int right_y_moveto = 45;

    int right_x1 = 214;
    int right_y1 = -20;
    int right_x2 = 375;
    int right_y2 = 20;
    int right_x3 = 193;
    int right_y3 = 130;

    heart_outline_paint.setColor(Color.RED); // Change the boundary color
    heart_outline_paint.setStrokeWidth(15);
    heart_outline_paint.setStyle(Paint.Style.STROKE);

    path.moveTo(left_x_moveto, left_y_moveto);
    path.cubicTo(left_x1, left_y1, left_x2, left_y2, left_x3, left_y3);
    path.cubicTo(right_x2, right_y2, right_x1, right_y1, right_x_moveto, right_y_moveto);

    path.close();

    canvas.drawPath(path, heart_outline_paint);
}

Paint.Join.MITER 是做你想做的那个。

The outer edges of a join meet at a sharp angle

现在这个 MITER 连接仅在角度 <= 90 度时有效。但在这里,根据您提供的值,角度为 90 度,因此 MITER 连接不起作用。我修改了值以获得下图。图像不准确,但您需要尝试使用正确的值。


您可以设置 ROUND 加入方法来获得以下内容。

问题出在 Path.cubicTo()。在不压扁心形的情况下很难让 MITTER 加入工作。因此,我尝试使用 lineToarcTo 而不是 cubicTo 来创建一颗简单的心。下面是它的代码。您会注意到我将 canvas 旋转了 45 度,然后绘制了心形。这纯粹是为了方便,让坐标简单,不涉及毕达哥拉斯定理。

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    heart_outline_paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    heart_outline_paint.setStrokeJoin(Paint.Join.MITER);
    heart_outline_paint.setColor(Color.RED); // Change the boundary color
    heart_outline_paint.setStrokeWidth(15);
    heart_outline_paint.setStyle(Paint.Style.STROKE);
    path = new Path();

    float length = 100;
    float x = canvas.getWidth()/2;
    float y = canvas.getHeight()/2;

    canvas.rotate(45,x,y);

    path.moveTo(x,y);
    path.lineTo(x-length, y);
    path.arcTo(new RectF(x-length-(length/2),y-length,x-(length/2),y),90,180);
    path.arcTo(new RectF(x-length,y-length-(length/2),x,y-(length/2)),180,180);
    path.lineTo(x,y);
    path.close();

    canvas.drawPath(path, heart_outline_paint);
}

这段代码的最终渲染图如下: