【问题标题】:Draw a heart on canvas在画布上画一颗心
【发布时间】:2014-04-01 01:57:00
【问题描述】:

我想在 Canvas 上画一个心形。我发现了不同的数学方程,但我无法将它们中的任何一个转换为我可以在 onDraw 方法中实现的代码。我希望在这里有一颗类似这种形状的心:

我所追求的形状方程:

【问题讨论】:

    标签: android canvas graph curve


    【解决方案1】:

    Android 绘图 API 不提供用于绘制任意方程曲线的工具。如果您愿意脱离为心脏找到的特定功能形式,您可以使用 api 支持的三次贝塞尔曲线绘制心脏(没有颜色效果)。您将创建一个Path,然后使用其cubicTo 方法添加曲线部分。然后您将使用Canvas#drawPath 渲染Path

    要使用三次贝塞尔曲线获得心形,请查看this example(恰好在 JavaScript 中,但这个想法应该很容易移植到 Android)。

    我不确定在心形中创建颜色渐变的最佳方法是什么。我的建议是使用贝塞尔曲线定义心脏的内边界和外边界,并将其设置为Paint 的剪辑区域。然后,您可以使用 Paint 进行渐变填充,以限制绘制渐变的位置。

    【讨论】:

      【解决方案2】:
      public class HeartShape extends FrameLayout {
      
          private Paint paint;
          public HeartShape(@NonNull Context context) {
              super(context);
              init();
          }
      
          private void init() {
              paint = new Paint(Paint.ANTI_ALIAS_FLAG);
              paint.setColor(Color.RED);
              paint.setStyle(Style.STROKE);
              setWillNotDraw(false);
          }
      
          public HeartShape(@NonNull Context context, @Nullable AttributeSet attrs) {
              super(context, attrs);
              init();
          }
      
          public HeartShape(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
              super(context, attrs, defStyleAttr);
              init();
          }
      
          public HeartShape(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
              super(context, attrs, defStyleAttr, defStyleRes);
              init();
          }
      
          @Override
          protected void onDraw(Canvas canvas) {
      
              Path path = createHeartPath(canvas.getClipBounds().right,canvas.getClipBounds().bottom);
      
              canvas.drawPath(path,paint);
      
              super.onDraw(canvas);
          }
      
          private Path createHeartPath(int width, int height) {
              Path path = new Path();
              path.moveTo(0,height/3f);
              path.lineTo(width,height/3f);
              path.moveTo(width/2f,0f);
              path.lineTo(width/2f,height);
      
              float pX = width/2f;
              float pY = (height/100f)*33.33f;
      
              float x1 = (width/100f)*50;
              float y1 = (height/100f)*5;
              float x2 = (width/100f)*90;
              float y2 = (height/100f)*10;
              float x3 = (width/100f)*90;
              float y3 = (height/100f)*33.33f;
      
              path.moveTo(pX,pY);
              path.cubicTo(x1, y1, x2, y2, x3, y3);
              path.moveTo(x3,pY);
      
              x1 = (width/100f)*90;
              y1 = (height/100f)*55f;
              x2 = (width/100f)*65;
              y2 = (height/100f)*60f;
              x3 = (width/100f)*50;
              y3 = (height/100f)*90f;
      
              path.cubicTo(x1, y1, x2, y2, x3, y3);
             // path.lineTo(pX,pY);
      
      
              x1 = (width/100f)*50;
              y1 = (height/100f)*5;
              x2 = (width/100f)*10;
              y2 = (height/100f)*10;
              x3 = (width/100f)*10;
              y3 = (height/100f)*33.33f;
      
              path.moveTo(pX,pY);
              path.cubicTo(x1, y1, x2, y2, x3, y3);
              path.moveTo(x3,pY);
      
              x1 = (width/100f)*10;
              y1 = (height/100f)*55f;
              x2 = (width/100f)*35f;
              y2 = (height/100f)*60f;
              x3 = (width/100f)*50f;
              y3 = (height/100f)*90f;
      
              path.cubicTo(x1, y1, x2, y2, x3, y3);
              //path.lineTo(pX,pY);
      
              path.moveTo(x3,y3);
              path.close();
      
              return path;
          }
      
      
      }
      

      Output

      去掉画线代码并设置paint.setStyle(Style.FILL);

      private Path createHeartPath(int width, int height) {
          Path path = new Path();
         //path.moveTo(0,height/3f);
         //path.lineTo(width,height/3f);
         //path.moveTo(width/2f,0f);
         //path.lineTo(width/2f,height);
      
          float pX = width/2f;
          float pY = (height/100f)*33.33f;
      
          float x1 = (width/100f)*50;
          float y1 = (height/100f)*5;
          float x2 = (width/100f)*90;
          float y2 = (height/100f)*10;
          float x3 = (width/100f)*90;
          float y3 = (height/100f)*33.33f;
      
          path.moveTo(pX,pY);
          path.cubicTo(x1, y1, x2, y2, x3, y3);
          path.moveTo(x3,pY);
      
          x1 = (width/100f)*90;
          y1 = (height/100f)*55f;
          x2 = (width/100f)*65;
          y2 = (height/100f)*60f;
          x3 = (width/100f)*50;
          y3 = (height/100f)*90f;
      
          path.cubicTo(x1, y1, x2, y2, x3, y3);
          path.lineTo(pX,pY);
      
      
          x1 = (width/100f)*50;
          y1 = (height/100f)*5;
          x2 = (width/100f)*10;
          y2 = (height/100f)*10;
          x3 = (width/100f)*10;
          y3 = (height/100f)*33.33f;
      
          path.moveTo(pX,pY);
          path.cubicTo(x1, y1, x2, y2, x3, y3);
          path.moveTo(x3,pY);
      
          x1 = (width/100f)*10;
          y1 = (height/100f)*55f;
          x2 = (width/100f)*35f;
          y2 = (height/100f)*60f;
          x3 = (width/100f)*50f;
          y3 = (height/100f)*90f;
      
          path.cubicTo(x1, y1, x2, y2, x3, y3);
          path.lineTo(pX,pY);
      
          path.moveTo(x3,y3);
          path.close();
      
          return path;
      }
      

      我们可以修改createHeartPath()方法的这个逻辑/绘图物理并获得更好的输出,欢迎新的建议和更改。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-25
        • 2015-02-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多