I have drawn a circle filled with black color in the canvas and I have set the background color of the canvas to red.
I want only the circle which is black color to appear as my view but I get the red color as well.
I tried using canvas.clipPath() it dint work. I searched the net and found out we need to disable hardware acceleration to get it work. I tried that but it still dint work.
Tried disabling the Hardware Acceleration for particular view:
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
And also to whole application:
android:hardwareAccelerated="false"
Dint work in both the cases.
Any ideas on how to make it work ?
Code:
And here I am clipping
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
path.reset();
left = 50;
top = 50;
right = getWidth()- 50;
bottom = getHeight()-50;
RectF rectf = new RectF(left, top, right, bottom);
path.arcTo(rectf, startAngle, sweepAngle);
path.lineTo(linex, liney);
canvas.clipPath(path);
canvas.drawPath(path, paint);
//canvas.restore();
}
This is not what clip path is for. When you draw a path and then clip it - it means that the rest of the things you will draw on the canvas from that point will be masked by the path.
In your case you draw a red background before clipping the canvas - so it went all over the canvas, then you clipped it but draw only inside the path, so the clipping was useless.
you can get what you need that in that code:
// Do not set any background to the view before
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
path.reset();
left = 50;
top = 50;
right = getWidth()- 50;
bottom = getHeight()-50;
RectF rectf = new RectF(left, top, right, bottom);
path.arcTo(rectf, startAngle, sweepAngle);
path.lineTo(linex, liney);
canvas.clipPath(path);
canvas.drawRect(0, 0, getWidth(), getHeight(), Red Paint in here);
canvas.drawPath(path, paint);
//canvas.restore();
}
That way you draw the background after pathClip
You will not see any red color because you draw all over the path right after it, if I am guessing right - you want to be able to draw a part of a circle in one color and the rest in other - you can achieve it if your path that you will clip will be the full circle and the path that you draw will be the part that you want to draw
Related
I'm using a simple custom view which draw a path and clip its children.
Code used :
private void config() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setShadowLayer(10.0f, 4.0f, 4.0f, DARK)
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(20);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
circlePath.reset();
circlePath.addCircle(cx, cy, circleRadius, Path.Direction.CW);
canvas.drawPath(circlePath, paint);
canvas.clipPath(circlePath);
super.dispatchDraw(canvas);
canvas.restore();
}
The path is fully transparent with only a white stroke. If there is no child inside this view container everything is fine.
Empty path :
Problem : I have noticed when a child is clipped, it seems that pixels appears around the white stroke, and only inside the path
Path with a black clipped children inside:
I zoomed and resized screenshots to better understand but also in real size pixels are visible.
I tried without shadowLayer but there is still pixels
Could someone tell me what is the problem source and how to fix it ?
RectF rect1 = new RectF(left, top, right, bottom)
canvas.drawRect(rect, paint);
Is there anyway I can change the color of rect1 by calling rect1.setColor, or
do I have to redraw in Canvas with a different paint?
You need to invalidate first and redraw the rectangle again with different color.
invalidate();
mCanvas.drawRect(rect, differentPaint);
Starting with Android 6 the drawOval method seems to draw a rectangle instead of a circle when paint style is set to Paint.Style.STROKE.
If paint style is set to the Paint.Style.FILL or FILL_AND_STROKE everything seems to be fine.
See how it looks in next pictures.
Pre Android 6
Android 6
The green rectangle is supposed to be the green circle from the scale
Note that the drawing is made in a rectangle with 1.0f by 1.0f dimensions.
Everything works fine on all Android versions excepting 6.0.
Thank you
I manage it by using helper function that re-scale the canvas to a bigger rectangle (100x100), draws the circle and the scale back the canvas to original size.
public static void drawOval(Canvas canvas, RectF rectangle, Paint paint, float scale) {
float originalStrokeWidth = paint.getStrokeWidth();
float upScaling = 100f;
paint.setStrokeWidth(originalStrokeWidth * upScaling);
canvas.save();
RectF newRect = new RectF();
newRect.left = rectangle.left*upScaling;
newRect.top = rectangle.top*upScaling;
newRect.right = rectangle.right*upScaling;
newRect.bottom = rectangle.bottom*upScaling;
canvas.scale(scale/upScaling, scale/upScaling);
canvas.drawOval(newRect, paint);
canvas.restore();
paint.setStrokeWidth(originalStrokeWidth);
}
public static void drawOval(Canvas canvas, RectF rectangle, Paint paint) {
drawOval(canvas, rectangle, paint, 1f);
}
So, where I had canvas.drawOval(rect, paint) I replace it with
CanvasUtils.drawOval(canvas, rect, paint);
I have notice that "bug" happens only when I use a bitmap as canvas and draw that bitmap as background of the gauge.
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 am drawing a grid and I want it to be larger than the screen size so that a user can drag the screen left/right/up/down to get to the rest of the grid.
What is the best way to do that? I've tried drawing a larger bitmap to the canvas, but didn't get anywhere.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
Bitmap testBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888);
canvas.drawBitmap(testBitmap, 0, 0, paint);
canvas.drawPaint(paint);
//other grid drawing code here
}
I used the View's scrollBy() method in the onTouch method of the Activity. It worked.
You can probably use the canvas.translate(x, y) method. That will adjust the origin for your canvas in relation to the screen. So canvas.translate(10, 10) will make you canvas origin (0, 0) be at the point of (10, 10) on the screen. Use a negative translation to scroll the screen.