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 ?
Related
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.
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 have developed a custom rounded LinearLayout and I want to add 1px border.
Here my code :
public class MyLinearLayout extends LinearLayout {
private float radius;
private Path path = new Path();
private RectF rect = new RectF();
public MyLinearLayout(Context context)
{
super(context);
radius = 20;
setWillNotDraw(false);
}
#Override
protected void onDraw(Canvas canvas) {
path.reset();
rect.set(0, 0, canvas.getWidth(), canvas.getHeight());
path.addRoundRect(rect, radius, radius, Direction.CCW);
// Add 1px border RED here ?
path.close();
canvas.clipPath(path);
}
}
Thanks for your help.
If you look closely at the rounded corners in your custom LinearLayout, you will probably see that the radius is not smooth. This is because there is a system limitation that does not support anti aliasing on Paths.
Here is a great tutorial from Erik Burke on how to properly create Views with rounded corners. Basically you will create an off-screen Bitmap, draw a RoundRectangle, and use an alpha compositing technique to merge the off-screen Bitmap with the custom LinearLayout Canvas' Bitmap.
As far as a border, you can can draw it by setting Paint.Style.FILL_AND_STROKE to the Paint.
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
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.