Round top corners with Path - java

I'm trying to clip the top-left and the top-right corners of Canvas in java. I understand you can just use addRoundRect for all the corners, but I'm unsure what to do for only the top corners.
This is what I currently have:
#Override
protected void onDraw(Canvas canvas) {
float radius = 12f;
Path clipPath = new Path();
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
//uh...
//clipPath.addRoundRect(rect, radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
}

You can use another overloading method addRoundRect() like this :
int width = view.getWidth();
int height = view.getHeight();
float[] radii = {0, 0, 0, 0, 0, 0, 0, 0};
if( mRadiusTop ) {
radii[0] = mRadius;
radii[1] = mRadius;
radii[2] = mRadius;
radii[3] = mRadius;
}
if( mRadiusBottom ) {
radii[4] = mRadius;
radii[5] = mRadius;
radii[6] = mRadius;
radii[7] = mRadius;
}
clipPath.addRoundRect(new RectF(0, 0, width, height), radii, Path.Direction.CW);
canvas.clipPath(clipPath);
I solved the problem by above code.

You can hack it. Just set the RectF larger by as many pixels as the radius of the rounded corners like this:
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight() + 12.0f); // draw a larger rect
I guess that you would have to set the paint color to full transparency (0x00fffffff).

Related

drawRoundRect in Android not working

I want to draw a rounded rectangle with drawRoundRect method in Android.
void drawRoundRect (RectF rect, float rx, float ry, Paint paint)
I'm using Android Studio, and my testing device use Android 6.0.1, API 23
This is part of my code. It works find when I put zeros in rx and ry.
public void draw(Canvas canvas){
canvas.drawColor(Color.WHITE);
canvas.drawRoundRect(rect, 0, 0, pnt);
}
This draws a black rectangle in my screen.
But when I try to make it rounded,
public void draw(Canvas canvas){
canvas.drawColor(Color.WHITE);
canvas.drawRoundRect(rect, 10, 10, pnt);
}
It draws nothing. This only draws white background....
I tried different numbers like 100, 3, 5, 0.03f etc in rx and ry,
but any numbers bigger than 0 make drawRoundRect() not working.
Is there anything wrong with my code...?
Make sure that coordinates in RectF that is used to draw rounded rectangle are correct. That means: rect.left < rect.right and rect.top < rect.bottom.
It seems that Android 7 corrects wrong coordinates itself and draws desired rounded rectangle, but Android 6 is drawing nothing if there is problem with coordinates.
you can try this we have a little calculation but it works awesomely
private void drawRoundedRect(Canvas canvas, float left, float top, float right, float bottom) {
float radius = getHeight() / 2;
canvas.drawCircle(radius, radius, radius, mainPaint);
canvas.drawCircle(right - radius, radius, radius, mainPaint);
canvas.drawRect(left + radius, top, right - radius, bottom, mainPaint);
}
or you can check this
RectF rect = new RectF(10,10,20,20);
canvas.drawRoundRect(rect , 0, 0, mPaint);
Try this,
Bitmap bitmap = Bitmap.createBitmap(
600, // Width
300, // Height
Bitmap.Config.ARGB_8888 // Config
);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setAntiAlias(true);
int offset = 50;
RectF rectF = new RectF(
offset, // left
offset, // top
canvas.getWidth() - offset, // right
canvas.getHeight() - offset // bottom
);
int cornersRadius = 25;
canvas.drawRoundRect(
rectF, // rect
cornersRadius, // rx
cornersRadius, // ry
paint // Paint
);
mImageView.setImageBitmap(bitmap);
You could do this,
RectF rect = new RectF(0f, 0f, width, height);
canvas.drawRoundRect(rect , 0, 0, mPaint);

How to rotate only the canvas behind the text

I have this function that animate the image canvas from resource drawable with text on the front.
I want to rotate the a green "star" only so the text stay intact
The idea is to rotate only the image canvas but no the text.
How do I do that?
This code is for Android Java
private Bitmap writeTextOnDrawable(int drawableId, String text, ImageView imv_promo,boolean isAnim) {
Bitmap bm = BitmapFactory.decodeResource(ctx.getResources(), drawableId).copy(Bitmap.Config.ARGB_8888, true);
Typeface tf = Typeface.createFromAsset(ctx.getAssets(), "RobotoCondensed-Italic.ttf");
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(ctx.getResources().getColor(R.color.white));
paint.setTypeface(tf);
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(convertToPixels(mContext, 17));
Rect textRect = new Rect();
paint.getTextBounds(text, 0, text.length(), textRect);
Canvas canvas = new Canvas(bm);
//If the text is bigger than the canvas , reduce the font size
if (textRect.width() >= (canvas.getWidth() - 4)) //the padding on either sides is considered as 4, so as to appropriately fit in the text
paint.setTextSize(convertToPixels(mContext, 7)); //Scaling needs to be used for different dpi's
//Calculate the positions
int xPos = (canvas.getWidth() / 2) - 6; //-2 is for regulating the x position offset
int yPos = (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2));
canvas.save();
canvas.rotate((float) 25, xPos, yPos);
canvas.drawText(text, xPos, yPos, paint);
canvas.restore();
Animation animation;
if(isAnim) {
animation = new RotateAnimation(0, 360, canvas.getWidth() / 2, canvas.getHeight() / 2);
animation.setRepeatMode(Animation.RESTART);
animation.setRepeatCount(Animation.INFINITE);
animation.setDuration(20000L);
imv_promo.startAnimation(animation);
}
return bm;
}

How show text in centre of each rectangle using onDraw

I'm trying to create a text view (black colour) containing numbers 1 to 7 (each number on top and in the centre of each grey rectangle - just like the image I've drawn below) but I'm not sure what properties I need to add in order to achieve this. I believe the code needs to go in the loop section but I don't what code. What can be done so that a number appears centralised in each grey rectangle?
desired outcome
current outcome
public class RectangleTextView extends View {
private final Paint mBackPaint = new Paint();
private final Paint mRedPaint = new Paint();
private int mSideRectWidth = 10;
public RectangleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
mBackPaint.setColor(Color.BLACK);
mRedPaint.setColor(Color.RED);
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (getWidth() == 0)
return;
//draw grey boxes
setBackgroundColor(Color.parseColor("#808080"));
int boxWidth = getWidth() / 7;
//draw black lines and/or draw text in centre of each rectangle
for (int i = 0; i < 7; i++) {
canvas.drawLine(mSideRectWidth + boxWidth * i, 0, mSideRectWidth + boxWidth * i, getHeight(), mBackPaint);
canvas.drawText(?);
}
//draw text in centre of each rectangle
?
//draw left end rectangle
canvas.drawRect(0, 0, mSideRectWidth, getHeight(), mRedPaint);
//draw right end rectangle
canvas.drawRect(getWidth() - mSideRectWidth, 0, getWidth(), getHeight(), mRedPaint);
}
}
Use canvas.drawText(). You can do it in the same loop that you draw the black lines.
for (int i = 0; i < 7; i++) {
canvas.drawLine(mSideRectWidth + boxWidth * i, 0, mSideRectWidth + boxWidth * i, getHeight(), mBackPaint);
float x = ...
float y = ...
canvas.drawText(Integer.toString(i + 1), x, y, mBlackPaint);
}
You will have to figure out the x and y value for the placement of the text. If you use paint.setTextAlign(Align.CENTER), then that simplifies the x value calculation, it's just halfway between the black lines.
Use the Paint.getTextBounds() method to get the bounding area of the text, then the exact center vertically and horizontally can be extracted from the resulting Rect object:
Paint paint = new Paint();
paint.setTextSize( textSize );
Rect bounds = new Rect();
if( text != null )
paint.getTextBounds(text, 0, text.length(), bounds);
else
bounds.set(0,0,0,0);
location.x -= bounds.exactCenterX();
location.y -= bounds.exactCenterY();

RoundRectangle2D clip is not very smooth

I have a JPanel that i want to clip the corners so that it has rounded edge.
Here is what i am doing.
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(color);
Shape s = new RoundRectangle2D.Double(0, 0, width, height, arc, arc);
g.setClip(s);
So notice that i am setting the clipping to a RoundRectangle2D. Also i am setting anti-aliasing still my rounded edges are really jagged.
Soft clipping example this link has a way to do soft rounded edges for a image. How do i apply the same to a JPanel?
because clipping is not aliased, you see the jagged edges. try a border instead:
p.setBorder(new RoundedBorder(p.getBackground(), 2, 16));
where RoundedBorder is adapted from the text bubble class:
class RoundedBorder extends AbstractBorder {
private Color color;
private int thickness = 4;
private int radii = 8;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
private int pointerPad = 4;
RenderingHints hints;
RoundedBorder(
Color color, int thickness, int radii) {
this.thickness = thickness;
this.radii = radii;
this.color = color;
stroke = new BasicStroke(thickness);
strokePad = thickness / 2;
hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int bottomPad = pad + strokePad;
insets = new Insets(pad, pad, bottomPad, pad);
}
#Override
public Insets getBorderInsets(Component c) {
return insets;
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
return getBorderInsets(c);
}
#Override
public void paintBorder(
Component c,
Graphics g,
int x, int y,
int width, int height) {
Graphics2D g2 = (Graphics2D) g;
int bottomLineY = height - thickness;
RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
0 + strokePad,
0 + strokePad,
width - thickness,
bottomLineY,
radii,
radii);
Area area = new Area(bubble);
g2.setRenderingHints(hints);
Area spareSpace = new Area(new Rectangle(0, 0, width, height));
spareSpace.subtract(area);
g2.setClip(spareSpace);
g2.clearRect(0, 0, width, height);
g2.setClip(null);
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
}
}
}
If you want anti-aliased corners, use TexturePaint instead of clipping. It is the same as clipping, only faster. Use it with anti-alias on.
Just Google "TexturePaint examples".

Adding a round frame circle on rounded bitmap

Im trying to create a round frame around my bitmap!
With this code im able to make my bitmap round:
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff4242DB;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = bitmap.getWidth()/2;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
//canvas.drawCircle(0, 0, bitmap.getWidth(), paint);
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
What i've tried is to draw a circle(the outcommented line) with canvas, but It had no result.
Does anyone know how I can add a circular border around it?
EDIT
When I use the line:
canvas.drawCircle(0, 0, bitmap.getWidth(), paint);
The effect is, that 3 corners get rounded but the upper left stays the same(90 degrees)
But I can't see any line or circle!
Update
There now is RoundedBitmapDrawable and a corresponding factory in the Support library I recommend to use that, unless more flexibility is required.
Original Answer
You have to draw the circle after the bitmap. This is what did the trick for me.
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int radius = Math.min(h / 2, w / 2);
Bitmap output = Bitmap.createBitmap(w + 8, h + 8, Config.ARGB_8888);
Paint p = new Paint();
p.setAntiAlias(true);
Canvas c = new Canvas(output);
c.drawARGB(0, 0, 0, 0);
p.setStyle(Style.FILL);
c.drawCircle((w / 2) + 4, (h / 2) + 4, radius, p);
p.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
c.drawBitmap(bitmap, 4, 4, p);
p.setXfermode(null);
p.setStyle(Style.STROKE);
p.setColor(Color.WHITE);
p.setStrokeWidth(3);
c.drawCircle((w / 2) + 4, (h / 2) + 4, radius, p);
return output;
This does of course not include the fancy shadow of your example.
You might want to play around a little bit with the additional pixels.

Categories

Resources