I need to Draw a rectangle over image with touch event - android

I need to draw a rectangle over an image so that user can select a specific part of that image when the user selects a rectangular part must be drawn over it.
for example say if the user wants click image if a parking lot then user can draw rectangle on parking space

You have to override the onDraw() method on your view (ImageView), get the canvas and draw a rectangle. Something like that:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint myPaint = new Paint();
int left = 10; // left padding from your view left border
int top = 10; // top padding from your view top border
int rectWidth = 50;
int rectHeight = 30;
myPaint.setColor(Color.rgb(0, 0, 0));
myPaint.setStrokeWidth(10);
canvas.drawRect(left, top, left + rectWidth, top + rectHeight, myPaint);
}

Related

Android imageView with checkeredBackground and different size images ontop

Background
I have an ImageView which is used to display previews of a file.
I would like to have the ImageView with a checkerboard background, so that when a file with transparency is rendered on top (such as PNG and SVG files) the checkerboard shows through on the transparent parts.
I have found lots of questions on StackOverflow on how to create the checkered background and this question is not entirely specific to that.
I am currently doing it in code. I create a 2 by 2 bitmap (top left/bottom right are one colour, top right, bottom left are the other colour) where the size of each box is specified. Then i create the main bitmap by drawing this small bitmap repeatedly.
int checkeredBackgroundSquareSize= 16;
private static Bitmap getCheckeredBitmap(int size) {
size = (size > 0) ? size : DEFAULT_SQUARE_SIZE;
int colorOne = ContentApplication.appCtx().getColor(R.color.checkerboard_background_color_one);
int colorTwo = ContentApplication.appCtx().getColor(R.color.checkerboard_background_color_two);
// width/height is twice the size of the individual squares
Bitmap squareBitmap = Bitmap.createBitmap(size*2, size*2, Bitmap.Config.ARGB_8888);
Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bitmapPaint.setStyle(Paint.Style.FILL);
Canvas canvas = new Canvas(squareBitmap);
// draw 2 rectangles on 2 rows
// top left and bottom right are the first colour
// top right and bottom left are the second colour
// set colour for top left/bottom right squares
bitmapPaint.setColor(colorOne);
// Square 1 : top left
Rect rect = new Rect(0, 0, size, size);
canvas.drawRect(rect, bitmapPaint);
// Square 2 : bottom right
rect.offset(size, size);
canvas.drawRect(rect, bitmapPaint);
// change colour for top right/bottom left squares
bitmapPaint.setColor(colorTwo);
// Square 3 : top right
rect.offset(-size, 0);
canvas.drawRect(rect, bitmapPaint);
// Square 4: bottom left
rect.offset(size, -size);
canvas.drawRect(rect, bitmapPaint);
return squareBitmap;
}
I then create a Bitmap the size of my preview image, and use the checkered background bitmap to repeatedly draw on the canvas before the preview image is added on top.
// Create a Bitmap to render our SVG to
Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
// Create a Canvas to use for rendering
Canvas canvas = new Canvas(bitmap);
// If we don't specify a viewport box, then AndroidSVG will use the bounds of the Canvas
// as the viewport. So a scale of 1.0 corresponds to that size
canvas.scale(scaling,scaling );
// create the checkered background, indicating transparency
Bitmap square = getCheckeredBitmap(checkeredBackgroundSquareSize);
BitmapShader shader = new BitmapShader(square, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
Paint paint = new Paint();
paint.setShader(shader);
// in your draw method
canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, paint);
The issue
My previews can be different sizes, for example 100x100, 6000x2000 etc As i am creating the initial bitmap on these sizes, the final image for the files all render looking like the squares on the checkered background are different sizes.
I need to have the checkerboard look exactly the same regardless of the overlaid image's size.
Is there a way to set a background image for an ImageView to be an image. I can only see how to set it to a drawable and I can not see how to define a checkboard as an xml drawable.
Mike M gave the answer that solved my issue. See Mike's comments to the first post
Create your own Drawable that renders the checkerboard
public class CheckerboardDrawable extends Drawable {
// I inadvertently ran the example image with Paint.ANTI_ALIAS_FLAG, but
// we actually don't want that 'cause we're looking for crisp, clean lines.
private final Paint paint = new Paint();
private int checkeredBackgroundSquareSize = 16;
private int colorOne = Color.LTGRAY;
private int colorTwo = Color.WHITE;
#Override
public void draw(#NonNull Canvas canvas) {
final Rect bounds = getBounds();
final int squareSize = checkeredBackgroundSquareSize;
final int columns = bounds.width() / squareSize + 1;
final int rows = bounds.height() / squareSize + 1;
canvas.translate(bounds.left, bounds.top);
for (int c = 0; c < columns; c++) {
for (int r = 0; r < rows; r++) {
paint.setColor((c + r) % 2 == 0 ? colorOne : colorTwo);
final int x = c * squareSize;
final int y = r * squareSize;
canvas.drawRect(x, y, x + squareSize, y + squareSize, paint);
}
}
canvas.translate(-bounds.left, -bounds.top);
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
#Override
public void setAlpha(int alpha) {}
#Override
public void setColorFilter(#Nullable ColorFilter colorFilter) {}
}
Then add the drawable to the ImageView
final ImageView imageView = findViewById(R.id.image);
imageView.setBackground(new CheckerboardDrawable());

Moving the entire canvas

I'm making an Android game and I have shaped that I am drawing and they get big enough to leave the screen, I want to be able to move the canvas itself, so that I can center those shapes into the screen, and then go back to them being gone.
Is there such a way to move the canvas? i.e
canvas.move(10, 10);
You can translate the canvas, draw your game and than restore it. You can also draw part of it, translate and draw some more and than restore and continue drawing.
For example:
int offsetX = 10;
int offsetY = 10;
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.translate(offsetX, offsetY);
canvas.drawRect(box.x, box.y, box.x2, box.y2, paint);
canvas.restore();
}
Other option is to define an x,y offset that represents the amount you want to move the canvas and for each draw add this offset to the drawing.
For example:
int offsetX = 10;
int offsetY = 10;
protected void onDraw(Canvas canvas) {
canvas.drawRect(offsetX + box.x, offsetY + box.y, offsetX + box.x2, offsetY + box.y2, paint);
}

How canvas.drawRect draws a rectangle

I have to create a custom view where I have to draw a rectangle. I'm trying to use the canvas.drawRect method. I wanted to create rectangles somethig like this
the gray colored one is my custom view which is extending the View class.
Inside the onDraw method I'm trying to draw the rectangle.
But actually I'm confused with the parameters of the drawRect method.
As per the documentation
/**
* Draw the specified Rect using the specified paint. The rectangle will
* be filled or framed based on the Style in the paint.
*
* #param left The left side of the rectangle to be drawn
* #param top The top side of the rectangle to be drawn
* #param right The right side of the rectangle to be drawn
* #param bottom The bottom side of the rectangle to be drawn
* #param paint The paint used to draw the rect
*/
What I assume is that left and top forms the x,y coordinates of the starting point, and right is the width and bottom is the height. But it doesn't seem to work that way.
I tried something like this to draw one rectangle but it does not draw anything
paint.setColor(Color.BLUE);
canvas.drawRect(5, canvas.getHeight()/2, 30, 30, paint );
Can anyone please tell how exactly a rectangle is drawn using these values?
It would be very helpful if someone could show the code to draw at least the first rectangle.
My requirement is like, the number of inner rectangles are dynamic, so if I pass some 4 to this View, it should create 4 equal width rectangles horizontally. something like
Thanks in advance!!
But actually I'm confused with the parameters of the drawRect method.
The drawRect method requires only two coordinates to draw a rectangle.
The top left corner and the bottom right corner. So the 4 points form these 2 coordinates
in your canvas. Hope it is clear from the below images
P1 and P2 are points formed by (left,top) and (right,bottom), So the drawn rectangle would be like this.
To draw rectangles dynamically like you have shown in you image , try something like this
int[] colors = new int[]{Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW}; // given some fixed colors
in you onDraw method
#Override
protected void onDraw(Canvas canvas) {
int padding = 5;
float rectangleWidth = (getMeasuredWidth() - padding * 2) / colors.length;
for (int i = 0; i < colors.length; i++) {
paint.setColor(colors[i]);
canvas.drawRect(padding + (rectangleWidth * i),
getMeasuredHeight() / 2,
padding + rectangleWidth * (i + 1),
getMeasuredHeight() - padding, paint
); // 5 px is the padding given to the canvas
}
}
drawRect(float left, float top, float right, float bottom, Paint paint)
It seems in your case the problem is that if right is less than left or bottom is less than top then the rectangle is not drawn. But it seems it happens only in some devices , as #David Medenjak commented
I also recommend you to use the View dimensions and not the Canvas dimensions, that is better to use getWidth() & getHeight() and not Canvas.getWidth() & Canvas.getHeight()
Use this method to draw rectangle at X & Y coordinate with width and height params
fun drawRectangle(left: Int, top: Int, right: Int, bottom: Int, canvas: Canvas, paint: Paint?) {
var right = right
var bottom = bottom
right = left + right // width is the distance from left to right
bottom = top + bottom // height is the distance from top to bottom
canvas.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), paint!!)
}
Usage
//drawing rectangle
drawRectangle(posX, posY, 60, 40, canvas, paint)

Draw rotated rectangles

I drew a rotated rectangle and I wanted to draw another one with the same size just above the first one and I can't get this done somehow the second rect don't get the right position
I give him the same left and right and change the bottom to the top of the first rect and the top to - top-top of the first rect
Here is the code for the first rect draw (the second draw is in my laptop and it is not near me)
int offset = 200;
int left = width/2;
int top = height/2;
int right = left + offset;
int bottom = top + offset;
canvas.save();
canvas.rotate(45, left + offset/2, top + offset/2);
canvas.drawRect(left, top, right, bottom, paint);
canvas.restore();

canvas.clipPath() not working even after disabling harware acceleration

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

Categories

Resources