Android Drawing Path while Zoom and Pinch - android

I'm drawing bitmap and trying to do some drawing over it using Canvas.for drawing i'm adding
path whenever user draw something on it surface. I have implemented pinch Zoom and drag features over bitmap but when user Zoom the bitmap and draw something on it then Path doesn't get draw appropriately. I'm using Matrix for pinch zoom and drag features.
My problem is using the Path with with Matrix.

This is a working example where you can see how to implement a draggable and zoomable Path:
MainActivity
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class DrawActivity extends Activity {
DrawView drawView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set full screen view
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
drawView = new DrawView(DrawActivity.this);
setContentView(drawView);
}
}
DrawView
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.WindowManager;
public class DrawView extends View {
Context ctx;
static final String TAG = "DrawView";
Paint paint = new Paint();
//These two constants specify the minimum and maximum zoom
private static float MIN_ZOOM = 3f;
private static float MAX_ZOOM = 10f;
private float scaleFactor = 3.f;
private ScaleGestureDetector detector;
//These two variables keep track of the X and Y coordinate of the finger when it first
//touches the screen
private float startX = 0f;
private float startY = 0f;
//These two variables keep track of the amount we need to translate the canvas along the X
//and the Y coordinate
private float translateX = 0f;
private float translateY = 0f;
//These two variables keep track of the amount we translated the X and Y coordinates, the last time we
//panned.
private float previousTranslateX = 0f;
private float previousTranslateY = 0f;
private boolean dragged = false;
// Used for set first translate to a quarter of screen
private float displayWidth;
private float displayHeight;
public DrawView(Context context)
{
super(context);
ctx = context;
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
displayWidth = metrics.widthPixels;
displayHeight = metrics.heightPixels;
translateX = displayWidth/4;
translateY = displayHeight/4;
previousTranslateX = displayWidth/4;
previousTranslateY = displayHeight/4;
detector = new ScaleGestureDetector(context, new ScaleListener());
setFocusable(true);
setFocusableInTouchMode(true);
// Path's color
paint.setColor(Color.GRAY);
paint.setAntiAlias(false);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
//We're going to scale the X and Y coordinates by the same amount
canvas.scale(scaleFactor, scaleFactor, 0, 0);
//We need to divide by the scale factor here, otherwise we end up with excessive panning based on our zoom level
//because the translation amount also gets scaled according to how much we've zoomed into the canvas.
canvas.translate((translateX) / scaleFactor, (translateY) / scaleFactor);
canvas.drawRect(0, 0, 100, 100, paint);
canvas.restore();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// First finger is on screen
//We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
//amount for each coordinates This works even when we are translating the first time because the initial
//values for these two variables is zero.
startX = event.getX() - previousTranslateX;
startY = event.getY() - previousTranslateY;
break;
case MotionEvent.ACTION_MOVE:
// first finger is moving on screen
// update translation value to apply on Path
translateX = event.getX() - startX;
translateY = event.getY() - startY;
break;
case MotionEvent.ACTION_UP:
// No more fingers on screen
// All fingers went up, so let's save the value of translateX and translateY into previousTranslateX and
//previousTranslate
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
// All touch events are sended to ScaleListener
detector.onTouchEvent(event);
return true;
}
class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
invalidate();
return true;
}
}
}

Related

Set max & min height for line being drawn using onDraw

I have a custom view in my project. In the view class I draw a line using onDraw method. The height of the line can be changed by swiping up and down.How can I set a max and min value for the height of that line?
This is my code
package com.example.richyrony.draw;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
/**
* Created by Richy & Rony on 26-01-2018.
*/
public class Line extends View {
PointF topLeft = new PointF(100, 100);
PointF topRight = new PointF(290, 100);
PointF bottomLeft = new PointF(100, 290);
PointF bottomRight = new PointF(290, 290);
private final int NONE = -1, TOUCH_TOP_LEFT = 0, TOUCH_TOP_RIGHT = 1, TOUCH_BOT_LEFT = 2, TOUCH_BOT_RIGHT = 3;
int currentTouch = NONE;
Float lineTwoStartx = 250f;
Float lineTwoStart = 50f;
Float lineTwoEndx = 250f;
Float lineTwoEnd = 200f;
Float lineOneStartx = 50f;
Float lineOneStart = 50f;
;
Float lineOneEndx = 50f;
Float lineOneEnd = 200f;
RectF touchArea = new RectF(0, 0, 350, 350);
Paint paint;
public Line(Context context) {
super(context);
paint = new Paint();
paint.setStrokeWidth(4);
paint.setColor(Color.parseColor("#000000"));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(lineOneStartx, lineOneStart, lineOneEndx, lineOneEnd, paint);
canvas.drawLine(lineTwoStartx, lineTwoStart, lineTwoEndx, lineTwoEnd, paint);
canvas.drawLine(lineOneEndx, lineOneEnd, lineTwoEndx, lineTwoEnd, paint);
canvas.drawLine(lineOneStartx, lineOneStart, lineTwoStartx, lineTwoStart, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
//The user just put their finger down.
//We check to see which corner the user is touching
//And set our global, currentTouch, to the appropriate constant.
case MotionEvent.ACTION_DOWN:
if (touchArea.contains(event.getX(), event.getY())) {
currentTouch = TOUCH_TOP_LEFT;
Toast.makeText(getContext(), "tf" + currentTouch, Toast.LENGTH_SHORT).show();
} else {
return false; //Return false if user touches none of the corners
}
return true; //Return true if the user touches one of the corners
//Now we know which corner the user is touching.
//When the user moves their finger, we update the point to the user position and invalidate.
case MotionEvent.ACTION_MOVE:
switch (currentTouch) {
case TOUCH_TOP_LEFT:
lineOneEnd = event.getY();
invalidate();
return true;
}
//We returned true for all of the above cases, because we used the event
return false; //If currentTouch is none of the above cases, return false
//Here the user lifts up their finger.
//We update the points one last time, and set currentTouch to NONE.
case MotionEvent.ACTION_UP:
switch (currentTouch) {
case TOUCH_TOP_LEFT:
lineOneEnd = event.getY();
currentTouch = NONE;
invalidate();
return true;
}
return false;
}
return false;
}
}
And also if anyone has any idea on how to measure angles between two lines it would be helpful

Getting the touchdown to move a Rect object

I am trying to get this paddle_user to move vertically on when the screen is touched. But the paddle isn't moving. I've double checked the onTouch Code but i'm still no closer to finding out what I am doing wrong.
package com.nblsoft.pong;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;
public class PongLogic extends View implements View.OnTouchListener {
//set screen constrains in dip
Configuration configuration = this.getResources().getConfiguration();
int dpHeight = configuration.screenHeightDp; //The current height of the available screen space, in dp units, corresponding to screen height resource qualifier.
int dpWidth = configuration.screenWidthDp; //The current width of the available screen space, in dp units, corresponding to screen width resource qualifier.
//int smallestScreenWidthDp = configuration.smallestScreenWidthDp; //The smallest screen size an application will see in normal operation, corresponding to smallest screen width resource qualifier.
//DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
//float dpHeight = displayMetrics.heightPixels / displayMetrics.density;
//float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
private int dptopixel(int DESIRED_DP_VALUE){
final float scale = getResources().getDisplayMetrics().density;
return (int)((DESIRED_DP_VALUE) * scale + 0.5f);
}
private int pixeltodp(int DESIRED_PIXEL_VALUE){
final float scale = getResources().getDisplayMetrics().density;
return (int) ((DESIRED_PIXEL_VALUE) - 0.5f / scale);
}
//set paddle size, speed, position vector
int paddle_pos_x = 4 * (dptopixel(dpWidth)/100); //3 for 320x480, 10 for 1080x1920 etc.
int paddle_width = (dptopixel(dpWidth)/10); //
int paddle_pos_y = (dptopixel(dpHeight)/10); //48 for 320x480, 190 for 1080x1920 etc.
int paddle_height = (dptopixel(dpHeight)/100) + 3; //the paddle is 100% of the total height of phone.
int user_paddle_pos_x = 4 * (dptopixel(dpWidth)/100) ;
int user_paddle_pos_y = dptopixel(dpHeight) - ((dptopixel(dpHeight)/10) + (dptopixel(dpHeight)/100) + 3) ;
//User Paddle
public Rect paddle_user = new Rect(user_paddle_pos_x,
user_paddle_pos_y,
user_paddle_pos_x + paddle_width,
user_paddle_pos_y + paddle_height);
//AI paddle
Rect paddle_AI = new Rect(paddle_pos_x,
paddle_pos_y,
paddle_pos_x + paddle_width,
paddle_pos_y + paddle_height);
//set ball position vector, Velocity vector, acceleration
//Override onDraw method
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Paint mytext = new Paint();
mytext.setColor(Color.WHITE);
// Draw Middle point
canvas.drawRect(0, ((dptopixel(dpHeight)) / 2), (dptopixel(dpWidth)), (((dptopixel(dpHeight)) / 2) + 2), mytext);
canvas.drawRect(paddle_user,mytext);
canvas.drawRect(paddle_AI, mytext);
//Practise Methods
//canvas.drawText(Integer.toString(dptopixel(dpHeight)),300,300,mytext);
//canvas.drawText(Integer.toString(dptopixel(dpWidth)), 400, 400, mytext);
//canvas.drawText(Integer.toString(dpHeight),500,500,mytext);
//canvas.drawText(Integer.toString(dpWidth),600,600,mytext);
//canvas.drawText("Fuck", 700, 700, mytext);
//canvas.drawRect(0,0,dptopixel(dpWidth),dptopixel(dpHeight),mytext);
}
//Override Touch method
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
paddle_user.offsetTo(10,0);
}
return true; //Event Handled
}
public PongLogic(Context context) {
super(context);
setBackgroundColor(Color.BLACK); //to set background
this.setFocusableInTouchMode(true); //to enable touch mode
this.setOnTouchListener(this);
}
}
You have to implement the OnTouchListener interface and do this.setOnTouchListener(this).
Edit:
public class CustomClass extends View implements View.OnTouchListener{}
then in your constructor you add this.setOnTouchListener(this);
Edit2:
Ok so I forgot to tell you but when you does some modification for exemple with you rect you have to call the draw method and to do that properly you call invalidate. So in your ontouch method add invalidate().
here is the code that I did if you wan to check (I just cut your code to have a easier exemple):
public class PongLogic extends View implements View.OnTouchListener {
//set ball position vector, Velocity vector, acceleration
Rect paddle_user = new Rect(0, 100, 100, 200);
public PongLogic(Context context, AttributeSet attrs) {
super(context, attrs);
this.setOnTouchListener(this);
setBackgroundColor(Color.BLACK); //to set background
this.setFocusableInTouchMode(true);
}
//Override onDraw method
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Paint mytext = new Paint();
mytext.setColor(Color.WHITE);
mytext.setStyle(Paint.Style.STROKE);
mytext.setStrokeWidth(2);
canvas.drawRect(paddle_user, mytext);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
paddle_user.offsetTo(0,0);
invalidate();
return false;
}
}
So what you missed was basically the invalidate() method. So what you did in the begging was not wrong with the first OnTouch method but better to do with the interface if you make a custom view.

Zooming and drag feature in SurfaceView

I'm trying to create a SurfaceView that can be zoomed and dragged. It implements an HTTP image stream that draws directly into the canvas
I've tried the following code and it kinda work... but it gives me problems in the borders. No idea of the reason why. Any help?
Full stream:
Zoomed image:
In the second image you can see multiple green lines that doesn't need to be there.
This is the class that handles this stream:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.SurfaceView;
import android.view.WindowManager;
/**
* Created by fil on 07/12/15.
*/
public class ZoomSurfaceView extends SurfaceView {
//These two constants specify the minimum and maximum zoom
private static float MIN_ZOOM = 1f;
private static float MAX_ZOOM = 5f;
private float scaleFactor = 1.f;
private ScaleGestureDetector detector;
//These constants specify the mode that we're in
private static int NONE = 0;
private static int DRAG = 1;
private static int ZOOM = 2;
private boolean dragged = false;
private float displayWidth;
private float displayHeight;
private int mode;
//These two variables keep track of the X and Y coordinate of the finger when it first
//touches the screen
private float startX = 0f;
private float startY = 0f;
//These two variables keep track of the amount we need to translate the canvas along the X
//and the Y coordinate
private float translateX = 0f;
private float translateY = 0f;
//These two variables keep track of the amount we translated the X and Y coordinates, the last time we
//panned.
private float previousTranslateX = 0f;
private float previousTranslateY = 0f;
private final Paint p = new Paint();
private void init(Context context){
detector = new ScaleGestureDetector(getContext(), new ScaleListener());
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
}
public ZoomSurfaceView(Context context) {
super(context);
init(context);
}
public ZoomSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ZoomSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public ZoomSurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
public void resetZoom() {
}
public void drawBitmap(Canvas canvas, Bitmap b, Rect rect){
canvas.save();
//If translateX times -1 is lesser than zero, letfs set it to zero. This takes care of the left bound
if((translateX * -1) > (scaleFactor - 1) * displayWidth)
{
translateX = (1 - scaleFactor) * displayWidth;
}
if(translateY * -1 > (scaleFactor - 1) * displayHeight)
{
translateY = (1 - scaleFactor) * displayHeight;
}
//We need to divide by the scale factor here, otherwise we end up with excessive panning based on our zoom level
//because the translation amount also gets scaled according to how much we've zoomed into the canvas.
canvas.translate(translateX / scaleFactor, translateY / scaleFactor);
//We're going to scale the X and Y coordinates by the same amount
canvas.scale(scaleFactor, scaleFactor);
canvas.drawBitmap(b, null, rect, p);
/* The rest of your canvas-drawing code */
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
{
#Override
public boolean onScale(ScaleGestureDetector detector)
{
scaleFactor *= detector.getScaleFactor();
scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
return true;
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
mode = DRAG;
//We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
//amount for each coordinates This works even when we are translating the first time because the initial
//values for these two variables is zero.
startX = event.getX() - previousTranslateX;
startY = event.getY() - previousTranslateY;
break;
case MotionEvent.ACTION_MOVE:
translateX = event.getX() - startX;
translateY = event.getY() - startY;
//We cannot use startX and startY directly because we have adjusted their values using the previous translation values.
//This is why we need to add those values to startX and startY so that we can get the actual coordinates of the finger.
double distance = Math.sqrt(Math.pow(event.getX() - (startX + previousTranslateX), 2) +
Math.pow(event.getY() - (startY + previousTranslateY), 2));
if(distance > 0)
{
dragged = true;
distance *= scaleFactor;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_UP:
mode = NONE;
dragged = false;
//All fingers went up, so letfs save the value of translateX and translateY into previousTranslateX and
//previousTranslate
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
case MotionEvent.ACTION_POINTER_UP:
mode = DRAG;
//This is not strictly necessary; we save the value of translateX and translateY into previousTranslateX
//and previousTranslateY when the second finger goes up
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
}
detector.onTouchEvent(event);
//We redraw the canvas only in the following cases:
//
// o The mode is ZOOM
// OR
// o The mode is DRAG and the scale factor is not equal to 1 (meaning we have zoomed) and dragged is
// set to true (meaning the finger has actually moved)
if ((mode == DRAG && scaleFactor != 1f && dragged) || mode == ZOOM)
{
invalidate();
}
return true;
}
}
The code for adding the frames to the surface is the following:
if (!b.isRecycled()){
try {
Rect rect = new Rect(0, 0, frame.getWidth(), frame.getHeight());
Canvas canvas = frame.getHolder().lockCanvas();
synchronized (frame.getHolder()) {
if (!b.isRecycled()) {
frame.drawBitmap(canvas, b, rect);
b.recycle();
}
}
frame.getHolder().unlockCanvasAndPost(canvas);
} catch (java.lang.RuntimeException exc){
Dbg.d("ERROR", exc);
}
lastBitmap = b;
}
The code you posted is incomplete so its difficult to say what the problem is. I did drop your code into a quick demo project and didn't see any issues with the borders.
Just by looking at the screenshots: any chance that your image data is somehow wrapping? The 2nd screenshot looks like the bottom border is being drawn at the top of the image. Again tough to say without reproducible code.
Might try repainting the background before redrawing the bitmap
canvas.drawRect(rect, backgroundPaint);
frame.drawBitmap(canvas, b, rect);

Pan/Expand view/canvas in android

I've got this canvas which the user can add images/text etc to. If the user drags one of the items to either side of the canvas, it should expand if needed. I googled, but couldn't find any reasonable solution. Also, the canvas is about 90% of the screen width, and 70% of the height.. I'm not asking for an entire solution.. I just need a tip on how to do this (Links, docs, whatever)
Well, it's difficult to guess what you're trying to achieve. When you say "it should expand if needed", what do you mean? Expand to fill the parent view? Expand to it's intrinsic size?
Here's some (incomplete) code I use in a custom view class. Most of it is gleaned from multiple solutions on here and I give thanks to the original authors. The onDraw is the most interesting one. When you want to draw (where it says custom drawing here), you don't need to worry about translation or scaling as the canvas itself is translated and scaled. In other words, your x and y co-ords are relative to the view size - simply multiply them by scale.
public class LightsViewer extends ImageView {
private float scale;
// minimum and maximum zoom
private float MIN_ZOOM = 1f;
private float MAX_ZOOM = 5f;
// mid point between fingers to centre scale
private PointF mid = new PointF();
private float scaleFactor = 1.f;
private ScaleGestureDetector detector;
// drag/zoom mode
private final static int NONE = 0;
// current mode
private int mode ;
private float startX = 0f;
private float startY = 0f;
private float translateX = 0f;
private float translateY = 0f;
private float previousTranslateX = 0f;
private float previousTranslateY = 0f;
public LightsViewer(Context context) {
super(context);
detector = new ScaleGestureDetector(getContext(), new ScaleListener());
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
}
public LightsViewer(Context context, AttributeSet attrs) {
super(context,attrs);
detector = new ScaleGestureDetector(getContext(), new ScaleListener());
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int ZOOM = 2;
int DRAG = 1;
if (!allowZooming){return true;}
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
//We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
//amount for each coordinates This works even when we are translating the first time because the initial
//values for these two variables is zero.
startX = event.getX() - previousTranslateX;
startY = event.getY() - previousTranslateY;
break;
case MotionEvent.ACTION_MOVE:
if (mode == ZOOM){
Log.d("LIGHTS","ACTION_MOVE:Move but ZOOM, breaking");
break;}
translateX = event.getX() - startX;
translateY = event.getY() - startY;
//We cannot use startX and startY directly because we have adjusted their values using the previous translation values.
//This is why we need to add those values to startX and startY so that we can get the actual coordinates of the finger.
double distance = Math.sqrt(Math.pow(event.getX() - (startX + previousTranslateX), 2) +
Math.pow(event.getY() - (startY + previousTranslateY), 2)
);
if(distance > 0) {
dragged = true;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
midPoint(mid, event);
mode = ZOOM;
break;
case MotionEvent.ACTION_UP:
mode = NONE;
dragged = false;
//All fingers went up, so let's save the value of translateX and translateY into previousTranslateX and
//previousTranslate
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
//This is not strictly necessary; we save the value of translateX and translateY into previousTranslateX
//and previousTranslateY when the second finger goes up
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
}
detector.onTouchEvent(event);
//We redraw the canvas only in the following cases:
//
// o The mode is ZOOM
// OR
// o The mode is DRAG and the scale factor is not equal to 1 (meaning we have zoomed) and dragged is
// set to true (meaning the finger has actually moved)
if ((mode == DRAG && scaleFactor != 1f && dragged) || mode == ZOOM) {
this.invalidate();
}
return true;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (this.getImageMatrix().isIdentity()){return;}
if (allowZooming){
this.applyMatrix(this.getImageMatrix());
}
}
#Override
public void onDraw(Canvas canvas) {
canvas.save();
// scale the canvas
canvas.scale(scaleFactor, scaleFactor, mid.x, mid.y);
canvas.translate(translateX / scaleFactor, translateY / scaleFactor);
super.onDraw(canvas);
// do custom drawing here...e.g.
canvas.drawCircle(100,100, 3 / scaleFactor,light.paint);
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
return true;
}
}
// calculate the mid point of the first two fingers
private void midPoint(PointF point, MotionEvent event) {
// ...
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
Log.d("LIGHTS", x/2 + "," + y/2);
}
public void setMinZoom(float minZoom){
this.MIN_ZOOM = minZoom;
}
public void applyMatrix(Matrix matrix){
float[] matrixValues = new float[9];
matrix.getValues(matrixValues);
int x = (int)matrixValues[Matrix.MTRANS_X];
int y = (int)matrixValues[Matrix.MTRANS_Y];
float scale = matrixValues[Matrix.MSCALE_X];
if (lights!=null){
for (Light light:lights){
light.setX((int)((light.originalX * scale) + x));
light.setY((int)((light.originalY * scale) + y));
}
}
// if either the x or y translations are less than 0, then the image has been cropped
// so set the min zoom to the ratio of the displayed size and the actual size of the image
if (matrixValues[Matrix.MTRANS_X] < 0 || matrixValues[Matrix.MTRANS_Y] <0){
MIN_ZOOM = displayWidth / this.getDrawable().getIntrinsicWidth();
}else{
MIN_ZOOM = 1;
}
}
public void enableZooming(boolean enable){
allowZooming = enable;
}
public void setScale(float scale){
for (Light light:lights){
light.setX((int)(light.originalX * scale));
light.setY((int)(light.originalY * scale));
}
}
}

Canvas Motion draw circle

I need to draw a circle as per my finger move so i have write this code
package com.sport;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BlurMaskFilter;
import android.graphics.BlurMaskFilter.Blur;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class sport extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new TouchView(this));
}
class TouchView extends View {
Bitmap bgr;
Bitmap overlayDefault;
Bitmap overlay;
Paint pTouch;
int X;
int Y;
Canvas c2;
public TouchView(Context context) {
super(context);
bgr = BitmapFactory.decodeResource(getResources(), R.drawable.new1);
overlayDefault = BitmapFactory.decodeResource(getResources(),
R.drawable.original);
overlay = BitmapFactory.decodeResource(getResources(),
R.drawable.new1).copy(Config.ARGB_8888, true);
c2 = new Canvas(overlay);
pTouch = new Paint(Paint.DEV_KERN_TEXT_FLAG);
pTouch.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
pTouch.setColor(Color.TRANSPARENT);
// pTouch.setMaskFilter(new BlurMaskFilter(15, Blur.NORMAL));
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int ht = displaymetrics.heightPixels;
int wt = displaymetrics.widthPixels;
X = wt / 2;
Y = 0;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
X = (int) ev.getX();
Y = (int) ev.getY();
//invalidate();
break;
}
case MotionEvent.ACTION_MOVE: {
X = (int) ev.getX();
Y = (int) ev.getY();
/* Toast.makeText(getBaseContext(),"x is::"+ X,
Toast.LENGTH_LONG).show();
Toast.makeText(getBaseContext(),"Y is::"+ Y,
Toast.LENGTH_LONG).show();*/
//c2.drawCircle(X, Y, 70, pTouch);
/*System.out.println("x is"+X);
System.out.println("Y is"+Y);*/
invalidate();
break;
}
case MotionEvent.ACTION_UP:
X = (int) ev.getX();
Y = (int) ev.getY();
/*
* Toast.makeText(getBaseContext(),"x is::"+ X,
* Toast.LENGTH_LONG).show();
* Toast.makeText(getBaseContext(),"Y is::"+ Y,
* Toast.LENGTH_LONG).show();
*/
//invalidate();
break;
case MotionEvent.ACTION_POINTER_ID_MASK :
/*X = (int) ev.getX();
Y = (int) ev.getY();
invalidate();*/
break;
}
return true;
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int ht = displaymetrics.heightPixels;
int wt = displaymetrics.widthPixels;
int heightbitmap = bgr.getHeight();
int widthbitmap = bgr.getWidth();
int minus = wt - widthbitmap;
// draw background
canvas.drawBitmap(bgr, minus / 2, 0, null);
// copy the default overlay into temporary overlay and punch a hole
// in it
c2.drawBitmap(overlayDefault, 360, 0, null); // exclude this line to
// show all as you
Bitmap _scratch = BitmapFactory.decodeResource(getResources(), R.drawable.diff_6); // draw
//c2.drawBitmap(_scratch, 10, 10, pTouch);
if(X >= 470 & X <= 522)
{
if(Y >= 255 & Y<= 330)
{
//c2.drawRect(X, Y, 5, 5, pTouch);
double outer_radius = 0.5 * Math.sqrt((_scratch.getWidth()) * (_scratch.getWidth())+ (_scratch.getHeight()) * (_scratch.getHeight()));
float f = (float) outer_radius;
c2.drawCircle(X, Y, f, pTouch);
}
}
// draw the overlay over the background
canvas.drawBitmap(overlay, minus/2, 0, null);
}
}
}
Problem::
when i touch on screen circle are stay at right side of my finger Like this.
but i need it center of my finger please help on this
The problem is because you create 'overlay' with respect to the x and y cordinates from the touch event and later copying this onto the background with an offset (minus/2). Assuming your background image is smaller than the screen resolution the circle will always shift right and hence will look the circle is at the right of your finger.
If you use a background image which has same resolution as the screen dimensions , you will get properly drawn circle, with its centre at the point of touch.

Categories

Resources