Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I was wondering if it would be possible for my application to zoom into a textbox when selected. Since the application is meant for people who are generally older, I would like this to be a possible option. Also to let you all know, this isn't related to anything about WebView. The application is simply a set of textboxes.
Zoom in When SELECTED? There is a class on github by #JadeByfield89 which extends the EditText and make it pinch Zoomable .
CODE ZoomableEditText:
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
/**
* Created by Jade Byfield on 3/29/2014.
*/
// ImageView that draws a grid on top of it's canvas
public class ZoomEditTextView extends EditText {
// touch tools
private static final int INVALID_POINTER_ID = -1;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
// The Ôactive pointerÕ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
private float mPosX;
private float mPosY;
private float mLastTouchX;
private float mLastTouchY;
private Bitmap mBitmap = null;
private Paint mPaint;
private Path mPath;
private Paint mBitmapPaint;
private Paint mCirclePaint;
private Path mCirclePath;
private Paint mDrawingPaint;
private List<Path> mPaths = new ArrayList<Path>();
private List<Paint> mPaints = new ArrayList<Paint>();
private float mBrushSize = 12.0f;
private Drawable mDrawable;
private Paint mRectPaint;
private Context mContext;
public ZoomEditTextView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
this.mContext = context;
init();
}
public ZoomEditTextView(Context context) {
super(context, null, 0);
this.mContext = context;
init();
// this.setOnTouchListener(new OnTouchListener() {
//
// #Override
// public boolean onTouch(View v, MotionEvent me) {
//
// InputMethodManager imm = (InputMethodManager) mContext
// .getSystemService(mContext.INPUT_METHOD_SERVICE);
// imm.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT);
//
// return true;
// }
//
// });
}
private void init() {
// Create our ScaleGestureDetector
mScaleDetector = new ScaleGestureDetector(mContext, new ScaleListener());
// Sets up drawing tools
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mCirclePaint = new Paint();
mCirclePath = new Path();
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(Color.CYAN);
mCirclePaint.setStyle(Paint.Style.STROKE);
mCirclePaint.setStrokeJoin(Paint.Join.MITER);
mCirclePaint.setStrokeWidth(4f);
//
mDrawingPaint = new Paint();
mDrawingPaint.setAntiAlias(true);
mDrawingPaint.setDither(true);
mDrawingPaint.setColor(Color.GREEN);
mDrawingPaint.setStyle(Paint.Style.STROKE);
mDrawingPaint.setStrokeJoin(Paint.Join.ROUND);
mDrawingPaint.setStrokeCap(Paint.Cap.ROUND);
mDrawingPaint.setStrokeWidth(mBrushSize);
mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG) ;
mRectPaint.setStyle(Paint.Style.STROKE);
mRectPaint.setColor(Color.WHITE);
mDrawable = mContext.getResources().getDrawable(R.drawable.ic_launcher);
mDrawable.setBounds(0, 0, mDrawable.getIntrinsicWidth(),
mDrawable.getIntrinsicHeight());
// setDrawingCacheEnabled(true);
// buildDrawingCache();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
//
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
// canvas.drawRect(new Rect(0, 0, canvas.getWidth(),
// canvas.getHeight()), mRectPaint);
super.onDraw(canvas);
// mDrawable.draw(canvas);
// if (mBitmap != null && canvas != null) {
// canvas.drawBitmap(mBitmap, mPosX, mPosY, mPaint);
// }
canvas.restore();
}
// Listen for multi-touch drag event and redraw the view accordingly
#Override
public boolean onTouchEvent(MotionEvent event) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(event);
final int action = event.getAction();
switch (action) {
// a touch down
case MotionEvent.ACTION_DOWN: {
// Scale detector is not in progress
if (!mScaleDetector.isInProgress()) {
final float x = event.getX();
final float y = event.getY();
// Save the ID of this pointer
mActivePointerId = event.getPointerId(0);
// Remember where we started
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer
mActivePointerId = event.getPointerId(0);
break;
}
}
case MotionEvent.ACTION_MOVE: {
// Only move the image if the scale detector is not in progress
if (!mScaleDetector.isInProgress()) {
// Find the index of active pointer and save its position
final int pointerIndex = event.findPointerIndex(mActivePointerId);
final float x = event.getX(pointerIndex);
final float y = event.getY(pointerIndex);
// mBitmap = getDrawingCache();
// Calculate the distance moved
float dx = x - mLastTouchX;
float dy = y - mLastTouchY;
// Move the object
mPosX += dx;
mPosY += dy;
// Remember this touch position for the next move event
mLastTouchX = x;
mLastTouchY = y;
// Invalidate to request a redraw
invalidate();
// break;
} /*
* else {
*
* final float gx = mScaleDetector.getFocusX(); final float gy =
* mScaleDetector.getFocusY();
*
* final float gdx = gx - mLastGestureX; final float gdy = gy -
* mLastGestureY;
*
* mPosX += gdx; mPosY += gdy;
*
* invalidate();
*
* mLastGestureX = gx; mLastGestureY = gy;
*
* }
*/
break;
}
case MotionEvent.ACTION_UP: {
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(mContext.INPUT_METHOD_SERVICE);
imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
// Reset the active pointer id
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
// Extract the index of the pointer that left the touch sensor
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
if (event.getPointerCount() >= 2) {
mLastTouchX = event.getX(newPointerIndex);
mLastTouchY = event.getY(newPointerIndex);
}
mActivePointerId = event.getPointerId(newPointerIndex);
} else {
final int tempPointerIndex = event
.findPointerIndex(mActivePointerId);
mLastTouchX = event.getX(tempPointerIndex);
mLastTouchY = event.getY(tempPointerIndex);
}
break;
}
}
return true;
}
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
invalidate();
return true;
}
}
}
Related
Here is My code, I am trying to zoom at the specific area but my code is not working properly. I want my code to work as Autocad Canvas zoom in out can anyone know to zoom canvas just like AutoCAD canvas. I want to make the CAD application work the same as AutoCAD work please help me.
I want My code to work as zoom in-out canvas drag move canvas.
public class Custom_Canvas extends View implements View.OnTouchListener {
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
Paint paint = new Paint();
// See onTouchEvent!
private float initX = 0f;
private float initY = 0f;
// x and y coord of canvas center!
private float canvasX = 0f;
private float canvasY = 0f;
private boolean drag = false;
private boolean firstdraw = true;
ScaleGestureDetector scaleGestureDetector;
private float scalefactor = 1f;
private float scalePointX, scalePointY;
float min_zoom = 0.1f;
float max_zoom = 10f;
private float lastfocusX = -1;
private float lastfocusY = -1;
#SuppressLint("ClickableViewAccessibility")
public Custom_Canvas(Context context, AttributeSet attrs){
super(context, attrs);
this.setOnTouchListener(this);
scaleGestureDetector = new ScaleGestureDetector(context,new Scalelistener());
paint.setColor(Color.WHITE);
}
#SuppressLint("ClickableViewAccessibility")
public Custom_Canvas(Context context) {
super(context);
this.setOnTouchListener(this);
paint.setColor(Color.WHITE);
scaleGestureDetector = new ScaleGestureDetector(context,new Scalelistener());
}
#SuppressLint("DrawAllocation")
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
if(firstdraw){
canvasX = getWidth()/2f;
canvasY = getHeight()/2f;
firstdraw = false;
}
canvas.scale(scalefactor,scalefactor,scalePointX,scalePointY);
canvas.translate(canvasX,canvasY);
canvas.drawCircle(0,0,20f,paint);
// canvas.drawCircle(100,100,20f,paint);
canvas.restore();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
scaleGestureDetector.onTouchEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
float x = event.getX()/scalefactor;
float y = event.getY()/scalefactor;
// drag = true;
initX = x;
initY = y;
mActivePointerId = event.getPointerId(0);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
// case MotionEvent.ACTION_POINTER_DOWN:
final int p = event.findPointerIndex(mActivePointerId);
final float x1 = event.getX(p) / scalefactor;
final float y1 = event.getY(p) / scalefactor;
if (!scaleGestureDetector.isInProgress()) {
// if (drag) {
float dx = x1 - initX;
float dy = y1 - initY;
canvasX += dx ;
canvasY += dy ;
invalidate();
// }
}
initX = x1;
initY = y1;
break;
case MotionEvent.ACTION_POINTER_UP:
// drag = false;
final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
initX = event.getX(newPointerIndex)/scalefactor;
initY = event.getY(newPointerIndex)/scalefactor;
mActivePointerId = event.getPointerId(newPointerIndex);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// drag = false;
mActivePointerId = INVALID_POINTER_ID;
break;
}
return true;
}
private class Scalelistener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
#Override
public boolean onScale(ScaleGestureDetector detector) {
scalefactor *= detector.getScaleFactor();
scalePointX = detector.getFocusX();
scalePointY = detector.getFocusY();
Toast.makeText(getContext(), " "+scalePointX+" "+scalePointY, Toast.LENGTH_SHORT).show();
if(lastfocusX == -1){
lastfocusX = scalePointX;
}
if(lastfocusY == -1){
lastfocusY = scalePointY;
}
canvasX += (scalePointX - lastfocusX);
canvasY += (scalePointY - lastfocusY);
scalefactor = Math.max(min_zoom,Math.min(scalefactor,max_zoom));
lastfocusX = scalePointX;
lastfocusY = scalePointY;
invalidate();
return true;
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
lastfocusX = -1;
lastfocusY = -1;
return true;
}
#Override
public void onScaleEnd(ScaleGestureDetector detector) { }
}
I am building an app where a user can draw lines in a custom canvas with a finger (multiple fragments have a canvas and this works) using the Path class.
I also managed to use SharedPreferences to save and load the drawn lines but when loaded the lines start from the top left (i.e (0, 0)) and the shape has changed to lines with a slight curve at the start (I say start because I found that the line ends from where the touch started).
The start points are kept in Path but from what I can see there are no endpoints kept. Is there any way I can get the endpoints?
I have previously tried passing the required variables to another ArrayList that uses another constructor with the endpoints (found with a method used for when the finger stops touching the screen) but the drawings no longer showed on the canvas unlike before.
Edit
I have changed to finding multiple points as I believe that getting the endpoint won't be enough and have altered the shown code to show my attempt with getPosTan but no drawings get shown as the elements in testing are null for some reason, so it won't go in the else.
Update
I found that pathMeasure.getLength() produces 0.0 so it isn't going into the while and therefore resulting in null elements but I don't know why it's producing 0.0 as somePath isn't null
PaintView.java
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.EmbossMaskFilter;
import android.graphics.MaskFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
public class PaintView extends View {
public static int BRUSH_SIZE = 10;
public static final int DEFAULT_COLOR = Color.WHITE;
public static int DEFAULT_BG_COLOR = Color.GRAY;
private static final float TOUCH_TOLERANCE = 4;
private float mX, mY;
private Path mPath;
private Paint mPaint;
private static ArrayList<FingerPath> paths = new ArrayList<>();
private int currentColor;
private int backgroundColor = DEFAULT_BG_COLOR;
private int strokeWidth;
private boolean emboss;
private boolean blur;
private MaskFilter mEmboss;
private MaskFilter mBlur;
private Bitmap mBitmap;
public Canvas mCanvas;
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(DEFAULT_COLOR);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setXfermode(null);
mPaint.setAlpha(0xff);
mEmboss = new EmbossMaskFilter(new float[] {1, 1, 1}, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);
}
public ArrayList getPaths() {
return paths;
}
public ArrayList setPaths(ArrayList<FingerPath> list) {
return this.paths = list;
}
public void init(DisplayMetrics metrics) {
int height = metrics.heightPixels;
int width = metrics.widthPixels;
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
loadDrawing(mCanvas);
currentColor = DEFAULT_COLOR;
strokeWidth = BRUSH_SIZE;
}
public void normal() {
emboss = false;
blur = false;
}
public void clear() {
backgroundColor = DEFAULT_BG_COLOR;
paths.clear();
normal();
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
mCanvas.drawColor(backgroundColor);
for (FingerPath fp : paths) {
mPaint.setColor(fp.color);
mPaint.setStrokeWidth(fp.strokeWidth);
mPaint.setMaskFilter(null);
if (fp.emboss)
mPaint.setMaskFilter(mEmboss);
else if (fp.blur)
mPaint.setMaskFilter(mBlur);
mCanvas.drawPath(fp.path, mPaint);
}
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
private void touchStart(float x, float y) {
mPath = new Path();
FingerPath fp = new FingerPath(currentColor, emboss, blur, strokeWidth, mPath, x, y);
paths.add(fp);
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touchMove(float x, float y) {
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touchUp() {mPath.lineTo(mX, mY);}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN :
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE :
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP :
touchUp();
invalidate();
break;
}
return true;
}
private FloatPoint[] getPoint(Path somePath, float x, float y){
FloatPoint[] pointArray = new FloatPoint[20];
PathMeasure pathMeasure = new PathMeasure(somePath, false);
float length = pathMeasure.getLength();
float distance = 0f;
float speed = length / 20;
int counter = 0;
float[] aCoordinates = {x, y};
while ((distance < length) && (counter < 20)) {
pathMeasure.getPosTan(distance, aCoordinates, null);
pointArray[counter] = new FloatPoint(aCoordinates[0],
aCoordinates[1]);
counter++;
distance = distance + speed;
}
return pointArray;
}
public void loadDrawing(Canvas canvas) {
if (mCanvas != null) {
currentColor = DEFAULT_COLOR;
strokeWidth = BRUSH_SIZE;
if (! paths.isEmpty()) {
canvas.save();
mCanvas.drawColor(backgroundColor);
for (FingerPath fp : paths) {
mPaint.setColor(fp.color);
mPaint.setStrokeWidth(fp.strokeWidth);
mPaint.setMaskFilter(null);
if (fp.emboss)
mPaint.setMaskFilter(mEmboss);
else if (fp.blur)
mPaint.setMaskFilter(mBlur);
FloatPoint[] testing = getPoint(fp.path, fp.x, fp.y);
//need to figure out how to for loop testing
float sectionTestX = 0.0f;
float sectionTestY = 0.0f;
for (FloatPoint testingPoint : testing) {
if (sectionTestX == 0.0f && sectionTestY == 0.0f) {
sectionTestX = testingPoint.getX();
sectionTestY = testingPoint.getY();
continue;
} else {
fp.path.quadTo(sectionTestX, sectionTestY,
testingPoint.getX(), testingPoint.getY());
sectionTestX = testingPoint.getX();
sectionTestY = testingPoint.getY();
}
}
/*xTest = fp.x;
yTest = fp.y;*/
}
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
}
}
}
FloatPoint.java
public class FloatPoint {
static float x, y;
public FloatPoint(float x, float y) {
this.x = x;
this.y = y;
}
public static float getX() {
return x;
}
public static float getY() {
return y;
}
}
I am able to pinch zoom in/out (though its not perfect yet) i want to use 2 fingers to drag since single drag is for drawing.
is this where the ACTION_POINTER_DOWN is required?
please help me how i can have the paint app drag with 2 fingers?
Below is the code
Thank you!
public class paintView extends View {
private static final int INVALID_POINTER_ID = -1;
private float mPosX;
private float mPosY;
private int mActivePointerId = INVALID_POINTER_ID;
private final ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
Paint paint;
Path path;
public paintView(Context context) {
super(context, null, 0);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
paint = new Paint();
path = new Path();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(8f);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
path.moveTo(x,y);
return true;
}
case MotionEvent.ACTION_MOVE: {
float x = ev.getX();
float y = ev.getY();
path.lineTo(x,y);
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
}
invalidate();
return true;
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// for moving around
// 2 finger drag 할때 필요할듯
canvas.translate(mPosX, mPosY);
// for zoom
canvas.scale(mScaleFactor, mScaleFactor);
//mImage.draw(canvas);
canvas.drawPath(path, paint);
//canvas.restore();
}
// zoom in gesture
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
final float scale = detector.getScaleFactor();
mScaleFactor = Math.max(.5f, Math.min(mScaleFactor * scale, 3.0f));
if (mScaleFactor < 5f) {
// 1 Grabbing
final float centerX = detector.getFocusX();
final float centerY = detector.getFocusY();
// 2 Calculating difference
float diffX = centerX - mPosX;
float diffY = centerY - mPosY;
// 3 Scaling difference
diffX = diffX * scale - diffX;
diffY = diffY * scale - diffY;
// 4 Updating image origin
mPosX -= diffX;
mPosY -= diffY;
}
invalidate();
return true;
}
}
}
I'm doing a simple courier system using android. How do I do if at the end of the delivery process client have to sign on the phone as the acknowledgement that they received the courier. How do i can do this using android. Any advice, suggestion is highly appreciated.
Performing a signature consume lots of space and a in phone device small area is not sufficient to take a signature from client at end of delivery process this is my idea.
Generate a list having delivery details.
--> at delivery time on click of delivered item a view opened.
--> in that view client can perform signature.
--> you can save that signature along with delivery details in DB
--> Delete or transfer items from to Deliver list to Delivered items(Which should be your another view approach)
This is my idea to perfor
m that task. For taking signature you can apply paint method and signature methods ask me if you want help on that too. thanks
package com.paintexample;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.View;
public class DrawView extends View {
private static final float STROKE_WIDTH = 5f;
/** Need to track this so the dirty region can accommodate the stroke. **/
private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
private Paint paint = new Paint();
private Path path = new Path();
/** Optimizes painting by invalidating the smallest possible area. */
private float lastTouchX;
private float lastTouchY;
private final RectF dirtyRect = new RectF();
public DrawView(Context context) {
super(context);
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(STROKE_WIDTH);
}
/** Erases the signature. */
public void clear() {
path.reset();
// Repaints the entire view.
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
lastTouchX = eventX;
lastTouchY = eventY;
// There is no end point yet, so don't waste cycles invalidating.
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
// Start tracking the dirty region.
resetDirtyRect(eventX, eventY);
// When the hardware tracks events faster than they are delivered,
// the
// event will contain a history of those skipped points.
int historySize = event.getHistorySize();
Logger.debug("historySize : " + historySize);
for (int i = 0; i < historySize; i++) {
float historicalX = event.getHistoricalX(i);
float historicalY = event.getHistoricalY(i);
expandDirtyRect(historicalX, historicalY);
path.lineTo(historicalX, historicalY);
}
// After replaying history, connect the line to the touch point.
// Logger.debug("eventX " + eventX);
// Logger.debug("eventY " + eventX);
//
// Logger.debug("lastTouchX " + lastTouchX);
// Logger.debug("lastTouchY " + lastTouchY);
//
// if (eventX == lastTouchX && eventY == lastTouchY) {
//
// path.addCircle(eventX, eventY, 20, Path.Direction.CW);
//
// }
path.lineTo(eventX, eventY);
break;
default:
Logger.debug("Ignored touch event: " + event.toString());
return false;
}
// Include half the stroke width to avoid clipping.
invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH), (int) (dirtyRect.top - HALF_STROKE_WIDTH), (int) (dirtyRect.right + HALF_STROKE_WIDTH), (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));
lastTouchX = eventX;
lastTouchY = eventY;
return true;
}
/** Called when replaying history to ensure the dirty region includes all
* points. */
private void expandDirtyRect(float historicalX, float historicalY) {
if (historicalX < dirtyRect.left) {
dirtyRect.left = historicalX;
} else if (historicalX > dirtyRect.right) {
dirtyRect.right = historicalX;
}
if (historicalY < dirtyRect.top) {
dirtyRect.top = historicalY;
} else if (historicalY > dirtyRect.bottom) {
dirtyRect.bottom = historicalY;
}
}
/** Resets the dirty region when the motion event occurs. */
private void resetDirtyRect(float eventX, float eventY) {
// The lastTouchX and lastTouchY were set when the ACTION_DOWN
// motion event occurred.
dirtyRect.left = Math.min(lastTouchX, eventX);
dirtyRect.right = Math.max(lastTouchX, eventX);
dirtyRect.top = Math.min(lastTouchY, eventY);
dirtyRect.bottom = Math.max(lastTouchY, eventY);
}
}
above is draw class
now add draw view in your activity like this.
//Assigning Drawing Board
drawView = new DrawView(this);
setContentView(view);
drawView.requestFocus();
linearLayout.addView(drawView);
you can your different methods of DrawView class for clear/paint and more enjoy
I have a simple Custom View and Scale Gesture detector implemented for the Pinch (zoom) gesture, just like this (found it on StackOverflow too):
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
public class MyImageView extends View {
private static final int INVALID_POINTER_ID = -1;
private Drawable mImage;
private float mPosX;
private float mPosY;
private float mLastTouchX;
private float mLastTouchY;
private int mActivePointerId = INVALID_POINTER_ID;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
public MyImageView(Context context) {
this(context, null, 0);
mImage=act.getResources().getDrawable(context.getResources().getIdentifier("imagename", "drawable", "packagename"));
mImage.setBounds(0, 0, mImage.getIntrinsicWidth(), mImage.getIntrinsicHeight());
}
public MyImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
}
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
Log.d("DEBUG", "X: "+mPosX+" Y: "+mPosY);
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
mImage.draw(canvas);
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
invalidate();
return true;
}
}
}
Then, when the View is Zoomed, I want to limit the Translation to go only to the boundaries of the Image that is being drawn in onDraw().
I thought I'll have that controled with Canvas.getClipBounds() just to see what's the zoomed image offset off of the Viewport, but then I cannot figure out how to control that.
To be more precise, I want my View not to translate the Image more than the 0 Left and 0 Top points of the View.
Thanks!
Change
canvas.translate(mPosX, mPosY);
To
if((mPosX<0)&&(mImage.getIntrinsicWidth()<canvas.getWidth()))
mPosX = 0;
if((mPosY<0)&&(mImage.getIntrinsicHeight()<canvas.getHeight()))
mPosY = 0;
canvas.translate(mPosX, mPosY);