I'm working with canvas im my application and I need to draw a circle.
To do that, I'm using the drawCicle(cx, cy, radious, paint) method for the canvas class.
The problem is that the circle's edges appear pixellated. And its kinf of oval.
This is my code:
public void drawCircle(){
Paint paint = new Paint();
paint.setColor(Color.rgb(52, 73, 94));
canvas.drawCircle(200, 300, 33, paint);
}
Use paint.setFlags(Paint.ANTI_ALIAS_FLAG)
This enables anti-aliasing => edges become smoother
Related
I want to draw an oval shape inside another oval shape, but the second one should be cut off when it reaches the border of the first one.
This is the desired result:
How can this be achieved?
I want to draw an oval shape inside another oval shape, but the second one should be cut off when it reaches the border of the first one.
As pskink said, you could use PorterDuffXfermode to implement this feature, here is an simple :
public class DrawView : View
{
public DrawView(Context context):base(context)
{
}
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
Paint paint = new Paint();
paint.SetARGB(255, 255, 0, 0);
RectF oval2 = new RectF(60, 100, 300, 200);
canvas.DrawOval(oval2, paint);
//PorterDuff.Mode.SrcAtop means Discards the source pixels that do not cover destination pixels. Draws remaining source pixels over destination pixels
paint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.SrcAtop));
paint.Color = Color.Black;
RectF oval3 = new RectF(110, 150, 350, 250);
canvas.DrawOval(oval3, paint);
this.SetLayerType(LayerType.Software, null);
paint.SetXfermode(null);
}
}
Effect :
I am new in android. I am trying to draw this image(match statistic)
and fill the image with color with 10% to 100% . I tried this much and this is image
this is the code
public class DrawView extends View {
Paint paint = new Paint();
public DrawView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.BLACK);
paint.setStrokeWidth(3);
canvas.drawRect(30, 30, 100, 100, paint);
paint.setStrokeWidth(0);
paint.setColor(Color.GRAY);
canvas.drawRect(33, 60, 97, 97, paint);
paint.setColor(Color.WHITE);
canvas.drawRect(33, 33, 97, 60, paint);
}
Any Suggestion will be much helpful for me.
Thanks in advance.
I would prepare two images - fully filled and not filled (only stroke). Having that, load them as two Bitmap objects and then draw like that:
float fillProgress = 0.1f; // let's say image is 10% filled
canvas.drawBitmap(onlyStroke, 0f, 0f, null); // draw just stroke first
canvas.save();
canvas.clipRect(
0f, // left
getHeight() - fillProgress * getHeight(), // top
getWidth(), // right
getHeight() // bottom
);
canvas.drawBitmap(filled, 0f, 0f, null); // region of filled image specified by clipRect will now be drawn on top of onlyStroke image
canvas.restore();
Using two images, outlined and filled e.g. below.
The code above does the following:
draw outline.
apply clip (crop) area.
draw filled shape with crop applied.
remove clip, image as desired.
Applying different clip sizes, you can get the % of fill you require. e.g.
At the first of my game, I draw some circles from alpha 0 to 255 using canvas(it's like making a fade_in animation by myself)
But if you see in picture(this picture captured in alpha 230),from alpha 0 to 254 these circles aren't smooth!(click on picture to see what I mean)
(and only when alpha become 255 the circles become smooth)
What's the problem and how can I fix this?
my code:
I have a game loop, that get canvas
canvas = gameView.getHolder().lockCanvas();
then in my view ,at first I set :
paintAlpha = 0;
paint = new Paint();
paint.setAntiAlias(true);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setAlpha(paintAlpha);
paint.setColor(Color.parseColor(color));
then in every loop(every ticks) I do this:
if(paintAlpha < 255) {
paintAlpha+=1;
paint.setAlpha(paintAlpha);
}
canvas.drawCircle(cx, cy, currentRadius, paint);
Solution:
Thanks to #nitesh.
The problem was because of surfaceView that can't set anti alias to canvas (in View you don't have this problem ,I don't know why)
By using Bitmap and draw on it and finally draw bitmap by canvas , the problem solved (instead of drawing on canvas directly)
Set the following property to paint object
paint.setAntiAlias(true);
For better understanding and other approaches refer this link
https://medium.com/#ali.muzaffar/android-why-your-canvas-shapes-arent-smooth-aa2a3f450eb5#.p9iktozdi
From the article
Draw a bitmap first if:
- You need to persist the image.
- You need to draw transparent pixels.
- Your shapes don’t change often and/or require time consuming operations.
Use anti-aliasing to draw smooth edges.
Avoid redraws on the bitmap if possible or else, clear a bitmap before redrawing.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (bitmap == null) {
bitmap = Bitmap.createBitmap(200,
200,
Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
}
bitmapCanvas.drawColor(
Color.TRANSPARENT,
PorterDuff.Mode.CLEAR); //this line moved outside if
drawOnCanvas(bitmapCanvas);
canvas.drawBitmap(bitmap, mLeftX, mTopY, p);
}
protected void drawOnCanvas(Canvas canvas) {
canvas.drawCircle(mLeftX + 100, mTopY + 100, 100, p);
}
you can approach this by
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
or
paint.setAntiAlias(true);
I tried to create a Maze with a moving ball and a hole using the Accelerometer Sensor. With the following code, the ball falls into the hole, but the performance is really bad, I set the Accelerometer Frequency to the fastest, but it's everything other than smooth. I made a second canvas, because so I could make a hole.
public RenderView(Context context, int width, int height) {
super(context);
playGround = new Rect(40, 40, width - 40, height - 40);
holes.addElement(new PointF(500f, 500f));
// Set background
this.setBackgroundResource(R.drawable.bottom);
// Set bitmap
woodGround= wood.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas();
bitmapCanvas.setBitmap(woodGround);
// Set eraser paint properties
eraserPaint.setAlpha(0);
eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
eraserPaint.setAntiAlias(true);
}
protected void onDraw(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG);
paint.setStyle(Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
if (ballInHole)
canvas.drawBitmap(ball, b.x, b.y, paint);
bitmapCanvas.drawBitmap(wall, 0, 0, paint);
bitmapCanvas.drawBitmap(wood, playGround, playGround, paint);
canvas.drawBitmap(bitmap, 0, 0, paint);
for (PointF h : holes) {
bitmapCanvas.drawCircle(h.x + radius, h.y + radius, radius,
eraserPaint);
}
if (!ballInHole)
canvas.drawBitmap(ball, b.x, b.y, paint);
invalidate();
}
It's solved very ugly, because I just draw the ball bellow the other bitmaps when he falls into a hole. Is there another way to do it?
The performance is also really bad, i set the Accelerometer-Sensor-Delay to the fastest, but the ball doesn't run smooth. When I remove the line canvas.drawBitmap(bitmap, 0, 0, paint);, then the ball is smoother, but then the wooden background is away.
The problem here is that you're doing A LOT of drawings all the time and that's take time to draw and the performance gets very low.
here a few tips on how you should approach it.
You probably better have one view with the static stuff (the background image and the holes) and on your layout have a second view on top of it just drawing the ball.
on the background image, do not call invalidate. That way you will draw the background just once.
and the top image (the ball only) you can invalidate, so it can redraw on the new position.
I'm not sure on this last part: but you may need to call invalidate(rect); passing the area where the ball was on the previous time, to make the background only re-draw that small area (instead of the whole screen)
happy coding.
I want to draw an image into shape of a Path and then add border on the Path. I was able to clip the image with Path but can't find a way to add border on it. I though it would be simple because the API supports Paint object on Canvas.draw* methods.
I asked another question at: Draw bitmap on current clip in canvas with border (Paint) and I accepted the answer. However, after that I found that I need to do a little bit more complicated processing. Because I use two options for clipping instead of one.
Below is my code to clip and image with two different Region.Op parameters
Bitmap srcImage = BitmapFactory.decodeStream(getAssets().open("panda.jpg"));
Bitmap bitmapResult = Bitmap.createBitmap(srcImage.getWidth(), srcImage.getHeight(), Bitmap.Config.ARGB_8888);
Path path = new Path();
// This is my border
Paint paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setColor(Color.RED);
paint.setStrokeWidth(2);
paint.setAntiAlias(true);
Canvas canvas = new Canvas(bitmapResult);
// Overlay two rectangles
path.addRect(10, 10, 70, 70, Path.Direction.CCW);
path.addRect(40, 40, 120, 120, Path.Direction.CCW);
canvas.drawPath(path , paint);
canvas.clipPath(path, Region.Op.INTERSECT);
// Draw the circle
path.reset();
path.addCircle(40, 80, 20, Path.Direction.CCW);
canvas.drawPath(path , paint);
canvas.clipPath(path, Region.Op.DIFFERENCE);
// The image is drawn within the area of two rectangles and a circle
// Although I suppose that puting Paint object into drawBitmap() method will add a red border on result image but it doesn't work
canvas.drawBitmap(srcImage, 0, 0, paint);
((ImageView)this.findViewById(R.id.imageView1)).setImageBitmap(bitmapResult);
Here is the result from my code: http://i.stack.imgur.com/8j2Kg.png
And this is what I expect: http://i.stack.imgur.com/iKhIr.png
Do I miss anything to make it work ?