Mo Adel
Mo Adel

Reputation: 1156

Draw a heart on canvas

I am looking to draw a heart shape on Canvas. I found different Math equation but i can't translate any of them into code that i can implement in onDraw Method. I am looking to have a heart similar to this shape here:

enter image description here

the Equation of shape that i am after where :

enter image description here

enter image description here

Upvotes: 4

Views: 7747

Answers (2)

Ashvin solanki
Ashvin solanki

Reputation: 4809

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

enter image description here

Remove drawing lines code and set 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;
}

enter image description here

We can modify this logic/drawing physics of createHeartPath() method and get better output, new suggestion and changes are welcome.

Upvotes: 4

Ted Hopp
Ted Hopp

Reputation: 234847

The Android drawing api doesn't provide tools for drawing arbitrary equation curves. If you're willing to depart from the particular functional form you found for a heart, you can draw the heart (without the color effects) using cubic Bezier curves, which are supported by the api. You would create a Path and then add curve sections using its cubicTo method. Then you would render the Path using Canvas#drawPath.

To get a heart shape using cubic Bezier curves, take a look at this example (which happens to be in JavaScript, but the idea should easily port to Android).

I'm not sure what the best approach would be to create a color gradient in a heart shape. My suggestion would be to define the inner and outer boundaries of the heart using Bezier curves and set that as the clip region for a Paint. Then you can do a gradient fill using that Paint to limit where the gradient is drawn.

Upvotes: 3

Related Questions