Reputation: 1156
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:
the Equation of shape that i am after where :
Upvotes: 4
Views: 7747
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
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;
}
We can modify this logic/drawing physics of createHeartPath()
method and get better output, new suggestion and changes are welcome.
Upvotes: 4
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