I'm making an application which can crop the image of the person. The layout of my application will give a better description
Here the rectangle will be used to capture the image defined by its length and width. The rectangle is movable. How would I go about re-sizing the rectangle. For eg. in WhatsApp when you touch the region inside the rectangle, the rectangle moves. If you touch the edges of rectangle, it provides the ability to re-size image suitable for cropping. So, I have 2 questions. 1) How to receive Touch events on edges of rectangle and 2) How would I re-size my rectangle. I'm using canvas to draw my rectangle. The code for this is as follows:
public class CustomView extends Views
{
public CustomView(Context context)
{
super(context);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);;
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(0, 0, 300, 300, paint);
}
}
You should implement the OnTouchListener and check in MotionEvent.ACTION_DOWN if you touch the rectangle and modify right, left, bottom and top of rectangle in MotionEvent.ACTION_MOVE
I provided a not tested example:
public class CustomView extends View {
private float left=0,right = 300, top = 0, bottom = 300;
public CustomView(Context context)
{
super(context);
setOnTouchListener( new OnTouchListener() {
float oldX, oldY;
#Override
public boolean onTouch(View v, MotionEvent event) {
boolean touch = false;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
touch = isTouchBorderRect();
break;
case MotionEvent.ACTION_UP:
touch = false;
case MotionEvent.ACTION_MOVE:
if (touch){
float newX = event.getRawX();
float newY = event.getRawY();
float deltaX = newX-oldX;
float deltaY = newY-oldY;
left-=deltaX;
right +=deltaX;
bottom += deltaY;
top -= deltaY;
}
break;
}
return false;
}
});
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);;
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(left, top, right, bottom, paint);
}
}
In isTouchBorderRect() method you should check if you have touched the rectangle.
This code is not tested but show the idea that you want to develop.
Related
I have a bitmap drawn to a canvas that I want to be able to paint transparent onto. When I move my finger to do the drawing, the paint does not paint to where my finger is. Instead it paints below and to the right of where I am touching.
#Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
bitmapCanvas.drawColor(Color.TRANSPARENT);
bitmapCanvas.drawCircle(x, y, 40, eraserPaint);
Matrix matrix = new Matrix();
matrix.postTranslate(tattoo.getX(), tattoo.getY());
canvas.drawBitmap(bitmap, matrix, paint);
}
public boolean onTouch(View view, MotionEvent event) {
x = (int) event.getX();
y = (int) event.getY();
invalidate();
return true;
}
I am working on a drawing app. And I already create a draw view that allow user to draw on the view.
The problem is , when I draw on it , it exceed the area of the image (please refer to the picture, the yellow line is exceeed the actual photo area), how can I stick the canvas size to the actual image ?
And how the imageview be zoomable? That means when user click on pen button, it draw, when user click again then it become zoom function.
Thanks. The zoom function can be tackle later and the problem of exceed area need to fix first
Here is the custom draw view in xml
<com.example.tool.DrawView
android:id="#+id/draw"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Here is the java
public class DrawView extends ImageView {
private int color = Color.BLACK;
private float width = 4f;
private List<Holder> holderList = new ArrayList<Holder>();
private class Holder {
Path path;
Paint paint;
Holder(int color, float width) {
path = new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(width);
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
}
}
public DrawView(Context context) {
super(context);
init();
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DrawView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
holderList.add(new Holder(color, width));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Holder holder : holderList) {
canvas.drawPath(holder.path, holder.paint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
holderList.add(new Holder(color,width));
holderList.get(holderList.size() - 1).path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
holderList.get(holderList.size() - 1).path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
invalidate();
return true;
}
public void resetPaths() {
for (Holder holder : holderList) {
holder.path.reset();
}
invalidate();
}
public void setBrushColor(int color) {
this.color = color;
}
public void setWidth(float width) {
this.width = width;
}
}
And I call it by:
DrawView pic = findViewById(R.id.draw);
pic.setImageBitmap(bitmap);
Thanks a lot for helping
Calculate the displayed image size first and then clamp the eventX and eventY to the bound of the displayed image. Code as below:
int imageViewH=imageView.getMeasuredHeight();//height of imageView
int imageViewW =imageView.getMeasuredWidth();//width of imageView
int drawableH =imageView.getDrawable().getIntrinsicHeight();//original height of underlying image
int drawableW=imageView.getDrawable().getIntrinsicWidth();//original width of underlying image
int displayH, displayW; // the shown height and width of the picture.
int leftX, rightX, topY, bottomY; // the shown edges of the picture.
if (imageViewH/drawableH <= imageViewW/drawableW){
displayW = drawableW*imageViewH/drawableH;//rescaled width of image within ImageView
displayH = imageViewH;
leftX = (imageViewW - displayW)/2; // left edge of the displayed image.
rightX = leftX + displayW; // right edge of the displayed image.
topY = 0; // top edg
bottomY = displayH; // bottom edge.
}else{
displayH = drawableH*imageViewW/drawableH;//rescaled height of image within ImageView
displayW = imageViewW;
leftX = 0; // left edge of the displayed image.
rightX = displayW; // right edge of the displayed image.
topY = (imageViewH - displayH)/2; // top edg
bottomY = topY + displayH; // bottom edge.
}
//TODO: clamp the eventX and eventY to the bound of leftX, rightX, topY, bottomY
Note: the code should be used only after your ImageView has its measured height and a drawable.
You can set a width of your DrawView programmatically to ImageView's width, if in ImageView's properties there's a true attribute adjustViewBounds.
I'm drawing a circle using 7 paint objects as below on a canvas in my android app. same paint object can be used more than one time to draw this circle.
Now I want to display color name of touched paint object, when user touch on each color.
How can I do this ?
Use on Touch Event for the same like :
public class TouchImage extends ImageView {
Paint paint = new Paint();
Point point = new Point();
public TouchImage(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setColor(Color.BLUE);
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(point.x, point.y, 10, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
point.x = event.getX();
point.y = event.getY();
invalidate();
}
return true;
}
class Point {
float x, y;
}
}
You should have the positions for all color circles.
Inside onTouchEvent() you can compare the distance between each color circle and touch position with color circles radius.
If distance is less than radius (and maybe greater than min value, so only the colors are touchable and not the empty area inside circle) you could otbtain the angle and determine selected color this way.
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
for (colorCircle c : allCircles) {
float distance = sqrt ((event.getX() - c.getX())^2 +
((event.getY() - c.getY())^2);
if (distance < c.getRadius()) {
for (coloredPart cPart : c) {
if (event.getX() > (Math.cos(cPart.getMinAngle) * c.getRadius)
+ c.getX() &&
event.getX() < (Math.cos(cPart.getMaxAngle) * c.getRadius)
+ c.getX() &&
event.getY() > (Math.sin(cPart.getMinAngle) * c.getRadius)
+ c.getY() &&
event.getY() < (Math.sin(cPart.getMaxAngle) * c.getRadius)
+ c.getY() && ) {
// cPart was touched
}
}
}
}
}
return true;
}
I have two doubts in canvas android.
They are explained below:
Firstly, I had drawn a row of circles on canvas, i want to capture the x and y coordinates of the circle(only on one circle)drawn so that I can draw a bitmap over the circle(in center).
Secondly, I want to imply touch event on circle i.e I want them to change color when some one touch them Can anybody help me with this?
for #2:
calculate the distance between the center of your point and the touch event - if the distance is smaller than the radius of your circle - you pressed on the circle
First you should create GridSector class for your "circle zone".
public class GridSector {
private int x = 0;
private int y = 0;
private Rect rect = new Rect(0, 0, 0, 0);
public GridSector(int x, int y, Rect rect) {
this.x = x;
this.y = y;
this.rect = rect;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Rect getRect() {
return rect;
}
public void setRect(Rect rect) {
this.rect.set(rect.left, rect.top, rect.right, rect.bottom);
}
}
Then Create view what you wanna touch.
public class GridSectorsView extends View {
GridSector currentSelectedSector;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawCircle(canvas); // draw your circles;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
invalidate(currentSelectedSector.getRect()); // update your circles (call onDraw Function ) ;
}
}
}
I'm trying to draw multiple rectangles. I want to be able to draw each rectangle by hand though. I can draw one but then once I call invalidate(), of course, the canvas gets cleared.
Is there another way to call the onDraw() so that the canvas doesn't get cleared?
Here's what I have:
I simply have a class which extends a SurfaceView and then
Override the onDraw
#Override
protected void onDraw(Canvas canvas)
{
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawRect(xCoor, yCoor, rectW, rectH, paint);
}
And then I Override an OnTouchEvent
#Override
public boolean onTouchEvent (MotionEvent event)
{
downX = Math.round(event.getX());
downY = Math.round(event.getY());
invalidate(); //clears canvas which I don't want
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
xCoor = downX;
yCoor = downY;
rectH = 0;
rectW = 0;
break;
case MotionEvent.ACTION_MOVE:
rectH = downY;
rectW = downX;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
Am I doing this completely wrong? :)
Any help would be appreciated.
Thanks!
You could add each rectangle to a list and iterate it onDraw like this:
import android.graphics.Rect;
private ArrayList<Rect> rectangles = new ArrayList<Rect>();
#Override
public boolean onTouchEvent (MotionEvent event) {
// ...
case MotionEvent.ACTION_UP:
rectangles.add(new Rect(xCoor, yCoor, rectW, rectH));
break;
// ...
}
#Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
for (Rect rect : rectangles) {
canvas.drawRect(rect, paint);
}
}