Android fix coordinates after scaling canvas by mid point - android

I have custom class extends from View, where I draw Bitmap and want to
scale and drag it with limits.
My task is creating ImageView which will be used in gallery, to see full photo.
Now I realized scale and drag but when I began to realize their limitation, noticed that after canvas.scale(mScale, mSсale, mid.x, mid.y) image position changes but my values mX, mY not change.
For this, I began making scale withour mid point, and change mX and mY manually.
So I have a problem with manually changing this values.
My Class:
public class ZoomImageView2 extends View {
private File imageFile;
private Bitmap bitmap;
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private PointF start = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private float d = 0f;
private float newRot = 0f;
private float[] lastEvent = null;
private int mX = 0, mY = 0;
private float mScale = 1f;
private Rect clipBounds_canvas;
private Handler mainHadler;
public ZoomImageView2(Context context) {
super(context);
mainHadler = new Handler(Looper.getMainLooper());
}
public ZoomImageView2(Context context, AttributeSet attrs) {
super(context, attrs);
mainHadler = new Handler(Looper.getMainLooper());
}
public ZoomImageView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mainHadler = new Handler(Looper.getMainLooper());
}
#Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
if (bitmap != null) {
canvas.save();
clipBounds_canvas = canvas.getClipBounds();
Log.w("SCALING_ZOOMIMAGE2", mX + " " + mY + " " + mScale);
canvas.scale(mScale, mScale);
canvas.drawBitmap(bitmap, mX, mY, new Paint());
canvas.restore();
}
}
public void setImageFile(final File imageFile) {
this.imageFile = imageFile;
new Thread(new Runnable() {
#Override
public void run() {
bitmap = BitmapHelper.getINSTANCE().getSampledBitmapFromFile(imageFile.getAbsolutePath(), getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().widthPixels);
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
if (bitmap.getWidth() >= bitmap.getHeight()) {
mStableScale = (float) getResources().getDisplayMetrics().widthPixels / (float) bitmap.getWidth();
} else {
mStableScale = (float) getResources().getDisplayMetrics().heightPixels / (float) bitmap.getHeight();
}
mScale = mStableScale;
invalidate();
}
});
}
}).start();
}
int mOldX, mOldY;
float mOldScale = 1f;
float mStableScale;
float maxScale = 5f;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
start.set(event.getX(), event.getY());
mode = DRAG;
lastEvent = null;
mOldX = mX;
mOldY = mY;
mOldScale = mScale;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
break;
case MotionEvent.ACTION_UP:
if (mScale < mStableScale) {
animateScaleTo(false);
}
if (mScale > maxScale) {
animateScaleTo(true);
}
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
mX = (int) ((event.getX() - start.x) / mScale + mOldX);
mY = (int) ((event.getY() - start.y) / mScale + mOldY);
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
mScale = (newDist / oldDist) * mOldScale;
mX = (int)-(getResources().getDisplayMetrics().widthPixels/2 * (mScale -1) - mOldX*mScale);
mY = (int)-(getResources().getDisplayMetrics().heightPixels/2 * (mScale -1) - mOldY*mScale);
//TODO!
}
if (lastEvent != null && event.getPointerCount() == 3) {
//newRot = rotation(event);
//float r = newRot - d;
//float[] values = new float[9];
//matrix.getValues(values);
//float tx = values[2];
//float ty = values[5];
//float sx = values[0];
//float xc = (view.getWidth() / 2) * sx;
//float yc = (view.getHeight() / 2) * sx;
//matrix.postRotate(r, tx + xc, ty + yc);
}
}
break;
}
invalidate();
return true;
}
private void animateScaleTo(final boolean forMax) {
new Thread(new Runnable() {
#Override
public void run() {
try {
int waiting = 1;
if (forMax) {
waiting = (int) (100 / ((mScale - maxScale) / 0.05));
} else {
waiting = (int) (100 / ((mStableScale - mScale) / 0.05));
}
if (waiting == 0) waiting = 1;
while (forMax ? mScale >= maxScale : mScale <= mStableScale) {
if (forMax) {
mScale -= 0.05;
} else {
mScale += 0.05;
}
mainHadler.post(new Runnable() {
#Override
public void run() {
invalidate();
}
});
Thread.sleep(waiting);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private void animateTranslateX(final boolean forEnd) {
new Thread(new Runnable() {
#Override
public void run() {
try {
int waiting;
if (forEnd) {
waiting = (int) (300f / (mX - (float) bitmap.getWidth() * mScale));
} else {
waiting = (int) (300f / (float) (mX));
}
if (waiting == 0) waiting = 1;
while (forEnd ? mX > ((float) bitmap.getWidth() * mScale) : mX > 0) {
mX -= 5;
mainHadler.post(new Runnable() {
#Override
public void run() {
invalidate();
}
});
Thread.sleep(waiting);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private void animateTranslateY(final boolean forEnd) {
new Thread(new Runnable() {
#Override
public void run() {
try {
int waiting;
if (forEnd) {
waiting = (int) (300 / (mY - (float) bitmap.getHeight() * mScale));
} else {
waiting = (int) (300 / (float) (mY));
}
if (waiting == 0) waiting = 1;
while (forEnd ? mY > ((float) bitmap.getHeight() * mScale) : mY > 0) {
mY -= 5;
mainHadler.post(new Runnable() {
#Override
public void run() {
invalidate();
}
});
Thread.sleep(waiting);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
point.set(getResources().getDisplayMetrics().widthPixels / 2, getResources().getDisplayMetrics().heightPixels / 2);
}
}
I have problem in place:
if (newDist > 10f) {
mScale = (newDist / oldDist) * mOldScale;
mX = (int)-(getResources().getDisplayMetrics().widthPixels/2 * (mScale -1) - mOldX*mScale);
mY = (int)-(getResources().getDisplayMetrics().heightPixels/2 * (mScale -1) - mOldY*mScale);
//TODO!
}
Here I must set values. Now its wrong.
I spend many time to solve this problem. Thanks a lot for help!
Sorry for bad English

As discussed in the comments, part of the solution is as follows: Modify the following:
mX = (int)-(getResources().getDisplayMetrics().widthPixels/2 * (mScale -1) - mOldX*mScale);
mY = (int)-(getResources().getDisplayMetrics().heightPixels/2 * (mScale -1) - mOldY*mScale);
to:
mX = (int)-(getResources().getDisplayMetrics().widthPixels/2 - mOldX*mScale);
mY = (int)-(getResources().getDisplayMetrics().heightPixels/2 - mOldY*mScale);
to remove an unnecessary additional multiplication step, which has the effect of scaling the image to a size that is too large.

Related

Canvas getting wrong coordinates for finger drawing after pinch to zoom

I create canvas finger drawing app like line brush which is on https://play.google.com/store/apps/details?id=jp.naver.linebrush.android, I done pinch to zoom functionality but problem is after zoom in and zoom out, not drawing properly position on canvas area. For more understanding I share my View class for canvas drawing:
public class DrawingView extends View {
// Zooming Code 16-6-2015 4.12pm
private static final int INVALID_POINTER_ID = -1;
public Bitmap mMyChracter;
private float mPosX;
private float mPosY;
private float mLastTouchX;
private float mLastTouchY;
private int mActivePointerId = INVALID_POINTER_ID;
View currentView;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
private float focusX;
private float focusY;
private float lastFocusX = -1;
private float lastFocusY = -1;
static final int IMG_WIDTH = 640;
static final int IMG_HEIGHT = 480;
static final int IMAGE_X_POS = 560;
static final int IMAGE_Y_POS = 20;
float sy;
float sx;
public static Context context;
// -------------------------------------
// ...................................
/*private final Bitmap bitmap;
private final int width;
private final int height;*/
private Matrix transform = new Matrix();
private Vector2D position = new Vector2D();
private float scale = 1;
private float angle = 0;
private TouchManager touchManager = new TouchManager(2);
private boolean isInitialized = false;
// Debug helpers to draw lines between the two touch points
private Vector2D vca = null;
private Vector2D vcb = null;
private Vector2D vpa = null;
private Vector2D vpb = null;
int mWidth;
int mHeight;
// ...............................
private final Paint mDefaultPaint;
private Paint mFillPaint;
float x, y;
private Canvas mLayerCanvas = new Canvas();
private Bitmap mLayerBitmap;
private Stack<DrawOp> mDrawOps = new Stack<>();
private Stack<DrawOp> mUndoOps = new Stack<>();
private SparseArray<DrawOp> mCurrentOps = new SparseArray<>(0);
// For Drag and Pan zoom Code initialization
private static float MIN_ZOOM = 1f;
private static float MAX_ZOOM = 2f;
private float scaleFactor = 1.f;
private static ScaleGestureDetector detector;
boolean mFlagDrawing;
private final Matrix mMatrix = new Matrix();
int y_old=0,y_new=0;int zoomMode=0;
float pinch_dist_old=0,pinch_dist_new=0;
int zoomControllerScale=1;//new and old pinch distance to determine Zoom scale
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
// We can be in one of these 3 states
static final int NONE = 0;
static final int PAN = 1;
static final int ZOOM = 2;
int mode = NONE;
private static final String TAG = "DebugTag";
// New Code
private Bitmap imgBitmap = null;
private int containerWidth;
private int containerHeight;
Paint background;
//Matrices will be used to move and zoom image
// Matrix matrix = new Matrix();
// Matrix savedMatrix = new Matrix();
// PointF start = new PointF();
float currentScale;
float curX;
float curY;
//We can be in one of these 3 states
// static final int NONE = 0;
// static final int DRAG = 1;
// static final int ZOOM = 2;
// int mode = NONE;
//For animating stuff
float targetX;
float targetY;
float targetScale;
float targetScaleX;
float targetScaleY;
float scaleChange;
float targetRatio;
float transitionalRatio;
float easing = 0.2f;
boolean isAnimating = false;
float scaleDampingFactor = 0.5f;
//For pinch and zoom
// float oldDist = 1f;
// PointF mid = new PointF();
private Handler mHandler = new Handler();
float minScale;
float maxScale = 8.0f;
float wpRadius = 25.0f;
float wpInnerRadius = 20.0f;
float screenDensity;
private GestureDetector gestureDetector;
public static final int DEFAULT_SCALE_FIT_INSIDE = 0;
public static final int DEFAULT_SCALE_ORIGINAL = 1;
private int defaultScale;
private static final String EXTRA_EVENT_LIST = "event_list";
private static final String EXTRA_STATE = "instance_state";
private ArrayList<MotionEvent> eventList = new ArrayList<MotionEvent>(100);
public DrawingView(Context context) {
this(context, null, 0);
}
public DrawingView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// detector = new ScaleGestureDetector(getContext(), new ScaleListener());
}
public DrawingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDefaultPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mDefaultPaint.setStyle(Paint.Style.STROKE);
mDefaultPaint.setStrokeJoin(Paint.Join.ROUND);
mDefaultPaint.setStrokeCap(Paint.Cap.ROUND);
mDefaultPaint.setStrokeWidth(40);
mDefaultPaint.setColor(Color.GREEN);
/*mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFillPaint.setStyle(Paint.Style.STROKE);
mFillPaint.setStrokeJoin(Paint.Join.ROUND);
mFillPaint.setStrokeCap(Paint.Cap.ROUND);
mDefaultPaint.setStrokeWidth(40);
mFillPaint.setColor(Color.GREEN);*/
setFocusable(true);
setFocusableInTouchMode(true);
setBackgroundColor(Color.WHITE);
setLayerType(LAYER_TYPE_SOFTWARE, null);
setSaveEnabled(true);
// Code for Zoom start
// detector = new ScaleGestureDetector(getContext(), new ScaleListener());
// Code for Zoom finish
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
private static float getDegreesFromRadians(float angle) {
return (float)(angle * 180.0 / Math.PI);
}
// Single Touch Code
#Override
public boolean onTouchEvent(#NonNull MotionEvent event) {
vca = null;
vcb = null;
vpa = null;
vpb = null;
final int pointerCount = MotionEventCompat.getPointerCount(event);
switch (MotionEventCompat.getActionMasked(event)) {
// switch(event.getAction()){
// switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// case MotionEventCompat.ACTION_POINTER_DOWN:
{
if (mFlagDrawing == true) {
/* final float xx = event.getX() / mScaleFactor;
final float yy = event.getY() / mScaleFactor;
mLastTouchX = xx;
mLastTouchY = yy;
mActivePointerId = event.getPointerId(0);*/
try {
touchManager.update(event);
if (touchManager.getPressCount() == 1) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
position.add(touchManager.moveDelta(0));
}
else {
if (touchManager.getPressCount() == 2) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
vcb = touchManager.getPoint(1);
vpb = touchManager.getPreviousPoint(1);
Vector2D current = touchManager.getVector(0, 1);
Vector2D previous = touchManager.getPreviousVector(0, 1);
float currentDistance = current.getLength();
float previousDistance = previous.getLength();
if (previousDistance != 0) {
scale *= currentDistance / previousDistance;
}
angle -= Vector2D.getSignedAngleBetween(current, previous);
}
}
invalidate();
}
catch(Throwable t) {
// So lazy...
}
System.out.println("mFlagDrawing: " + mFlagDrawing);
// Code for Zoom start
// detector.onTouchEvent(event);
// mScaleDetector.onTouchEvent(event);
// Code for Zoom finish
} else if (mFlagDrawing == false) {
System.out.println("mFlagDrawing: " + mFlagDrawing);
for (int p = 0; p < pointerCount; p++) {
final int id = MotionEventCompat.getPointerId(event, p);
DrawOp current = new DrawOp(mDefaultPaint);
current.getPath().moveTo(event.getX(), event.getY());
mCurrentOps.put(id, current);
}
}
// mFlagZoom = true;
// }
}
break;
case MotionEvent.ACTION_MOVE: {
// for(int p = 0; p < pointerCount; p++){
if (mFlagDrawing == true) {
/* final int pointerIndex = event.findPointerIndex(mActivePointerId);
final float xx = event.getX(pointerIndex) / mScaleFactor;
final float yy = event.getY(pointerIndex) / mScaleFactor;
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = xx - mLastTouchX;
final float dy = yy - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
}
mLastTouchX = xx;
mLastTouchY = yy;*/
try {
touchManager.update(event);
if (touchManager.getPressCount() == 1) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
position.add(touchManager.moveDelta(0));
// current.add(touchManager.moveDelta(0));
}
else {
if (touchManager.getPressCount() == 2) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
vcb = touchManager.getPoint(1);
vpb = touchManager.getPreviousPoint(1);
Vector2D current = touchManager.getVector(0, 1);
Vector2D previous = touchManager.getPreviousVector(0, 1);
float currentDistance = current.getLength();
float previousDistance = previous.getLength();
if (previousDistance != 0) {
scale *= currentDistance / previousDistance;
}
angle -= Vector2D.getSignedAngleBetween(current, previous);
}
}
invalidate();
}
catch(Throwable t) {
// So lazy...
}
System.out.println("mFlagDrawing: " + mFlagDrawing);
// Code for Zoom start
// detector.onTouchEvent(event);
// mScaleDetector.onTouchEvent(event);
// Code for Zoom finish
} else if (mFlagDrawing == false) {
System.out.println("mFlagDrawing: " + mFlagDrawing);
final int id = MotionEventCompat.getPointerId(event, 0);
DrawOp current = mCurrentOps.get(id);
final int historySize = event.getHistorySize();
for (int h = 0; h < historySize; h++) {
x = event.getHistoricalX(h);
y = event.getHistoricalY(h);
current.getPath().lineTo(x, y);
}
x = MotionEventCompat.getX(event, 0);
y = MotionEventCompat.getY(event, 0);
current.getPath().lineTo(x, y);
// position.add(current.getPath());
// }
}
}
break;
case MotionEvent.ACTION_UP:
// case MotionEventCompat.ACTION_POINTER_UP:
// {
if (mFlagDrawing == true) {
// mActivePointerId = INVALID_POINTER_ID;
try {
touchManager.update(event);
if (touchManager.getPressCount() == 1) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
position.add(touchManager.moveDelta(0));
}
else {
if (touchManager.getPressCount() == 2) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
vcb = touchManager.getPoint(1);
vpb = touchManager.getPreviousPoint(1);
Vector2D current = touchManager.getVector(0, 1);
Vector2D previous = touchManager.getPreviousVector(0, 1);
float currentDistance = current.getLength();
float previousDistance = previous.getLength();
if (previousDistance != 0) {
scale *= currentDistance / previousDistance;
}
angle -= Vector2D.getSignedAngleBetween(current, previous);
}
}
invalidate();
}
catch(Throwable t) {
// So lazy...
}
System.out.println("mFlagDrawing: " + mFlagDrawing);
// Code for Zoom start
// detector.onTouchEvent(event);
// mScaleDetector.onTouchEvent(event);
// Code for Zoom finish
} else if (mFlagDrawing == false) {
System.out.println("mFlagDrawing: " + mFlagDrawing);
for (int p = 0; p < pointerCount; p++) {
final int id = MotionEventCompat.getPointerId(event, p);
mDrawOps.push(mCurrentOps.get(id));
mCurrentOps.remove(id);
// }
updateLayer();
}
}
// }
break;
case MotionEvent.ACTION_CANCEL: {
if (mFlagDrawing == true) {
// mActivePointerId = INVALID_POINTER_ID;
try {
touchManager.update(event);
if (touchManager.getPressCount() == 1) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
position.add(touchManager.moveDelta(0));
}
else {
if (touchManager.getPressCount() == 2) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
vcb = touchManager.getPoint(1);
vpb = touchManager.getPreviousPoint(1);
Vector2D current = touchManager.getVector(0, 1);
Vector2D previous = touchManager.getPreviousVector(0, 1);
float currentDistance = current.getLength();
float previousDistance = previous.getLength();
if (previousDistance != 0) {
scale *= currentDistance / previousDistance;
}
angle -= Vector2D.getSignedAngleBetween(current, previous);
}
}
invalidate();
}
catch(Throwable t) {
// So lazy...
}
System.out.println("mFlagDrawing: " + mFlagDrawing);
// Code for Zoom start
// detector.onTouchEvent(event);
// mScaleDetector.onTouchEvent(event);
// Code for Zoom finish
} else if (mFlagDrawing == false) {
System.out.println("mFlagDrawing: " + mFlagDrawing);
for (int p = 0; p < pointerCount; p++) {
mCurrentOps
.remove(MotionEventCompat.getPointerId(event, p));
}
}
// mFlagZoom = true;
// }
}
break;
/*case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (event.getAction() & 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;
mLastTouchX = event.getX(newPointerIndex) / mScaleFactor;
mLastTouchY = event.getY(newPointerIndex) / mScaleFactor;
mActivePointerId = event.getPointerId(newPointerIndex);
}
break;
}*/
default:
return false;
}
invalidate();
return true;
}
#Override
protected void onSizeChanged(int w, int h, int oldW, int oldH) {
super.onSizeChanged(w, h, oldW, oldH);
/*mLayerBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mLayerCanvas.setBitmap(mLayerBitmap);*/
if(mLayerBitmap == null){
mLayerBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
}else{
Bitmap temporary = Bitmap.createScaledBitmap(mLayerBitmap, w, h, true);
mLayerBitmap = temporary;
}
mLayerCanvas = new Canvas(mLayerBitmap);
// mLayerCanvas.rotate(90);
/* matrix.setTranslate(1.5f,1.5f);
matrix.postRotate(90, 2.5f, 2.5f);*/
// updateLayer();
/* //Reset the width and height. Will draw bitmap and change
containerWidth = w;
containerHeight = h;
if(mLayerBitmap != null) {
int imgHeight = mLayerBitmap.getHeight();
int imgWidth = mLayerBitmap.getWidth();
float scale;
int initX = 0;
int initY = 0;
if(defaultScale == DrawingView.DEFAULT_SCALE_FIT_INSIDE) {
if(imgWidth > containerWidth) {
scale = (float)containerWidth / imgWidth;
float newHeight = imgHeight * scale;
initY = (containerHeight - (int)newHeight)/2;
matrix.setScale(scale, scale);
matrix.postTranslate(0, initY);
}
else {
scale = (float)containerHeight / imgHeight;
float newWidth = imgWidth * scale;
initX = (containerWidth - (int)newWidth)/2;
matrix.setScale(scale, scale);
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = scale;
minScale = scale;
}
else {
if(imgWidth > containerWidth) {
initY = (containerHeight - (int)imgHeight)/2;
matrix.postTranslate(0, initY);
}
else {
initX = (containerWidth - (int)imgWidth)/2;
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = 1.0f;
minScale = 1.0f;
}
invalidate();
}*/
}
private void updateLayer() {
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
for (DrawOp drawOp : mDrawOps) {
if (drawOp != null) {
drawOp.draw(mLayerCanvas);
}
}
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode()) {
return;
}
// if(mFlagDrawing == true){
if (!isInitialized) {
int w = getWidth();
int h = getHeight();
position.set(w / 2, h / 2);
isInitialized = true;
}
mWidth = mLayerBitmap.getWidth();
mHeight = mLayerBitmap.getHeight();
// Code for Zoom start
/* canvas.save();
canvas.scale(mScaleFactor, mScaleFactor, focusX, focusY);
canvas.translate(mPosX, mPosY);*/
// canvas.scale(scaleFactor, scaleFactor);
/*canvas.scale(mScaleFactor, mScaleFactor, super.getWidth() * 0.5f,
super.getHeight() * 0.5f);*/
// Code for Zoom finish
// canvas.save();
transform.reset();
transform.postTranslate(-mWidth / 2.0f, -mHeight / 2.0f);
// transform.postRotate(getDegreesFromRadians(angle));
transform.postScale(scale, scale);
transform.postTranslate(position.getX(), position.getY());
canvas.drawBitmap(mLayerBitmap, transform, null);
// }
// else if(mFlagDrawing == false){
// canvas.drawBitmap(mLayerBitmap, 0, 0, null);
for (int i = 0; i < mCurrentOps.size(); i++) {
DrawOp current = mCurrentOps.valueAt(i);
if (current != null) {
current.draw(canvas);
}
}
// }
// Code for Zoom
// canvas.restore();
}
public void operationClear() {
mDrawOps.clear();
mUndoOps.clear();
mCurrentOps.clear();
updateLayer();
}
public void operationUndo() {
if (mDrawOps.size() > 0) {
mUndoOps.push(mDrawOps.pop());
updateLayer();
}
}
public void operationRedo() {
if (mUndoOps.size() > 0) {
mDrawOps.push(mUndoOps.pop());
updateLayer();
}
}
public void setPaintStrokeWidth(float widthPx) {
mDefaultPaint.setStrokeWidth(widthPx);
}
public void setPaintOpacity(int percent) {
int alphaValue = (int) Math.round(percent * (255.0 / 100.0));
mDefaultPaint.setColor(combineAlpha(mDefaultPaint.getColor(),
alphaValue));
}
public void setPaintColor(String color) {
mDefaultPaint.setColor(combineAlpha(Color.parseColor(color), mDefaultPaint.getAlpha()));
}
public void setPaintColor(int color) {
mDefaultPaint.setColor(combineAlpha(color, mDefaultPaint.getAlpha()));
}
public void setPaintMaskFilter(MaskFilter filter) {
mDefaultPaint.setMaskFilter(filter);
}
public void setPaintShader(BitmapShader shader) {
mDefaultPaint.setShader(shader);
}
public void setPaintColorFilter(ColorFilter colorFilter) {
mDefaultPaint.setColorFilter(colorFilter);
}
private static int combineAlpha(int color, int alpha) {
return (color & 0x00FFFFFF) | ((alpha & 0xFF) << 24);
}
private static class DrawOp {
private float x,y;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Path mPath = new Path();
public DrawOp(Paint paint) {
reset(paint);
}
/*public void add(Vector2D moveDelta) {
// TODO Auto-generated method stub
this.x += moveDelta.getX();
this.y += moveDelta.getY();
}*/
void reset(Paint paint) {
mPath.reset();
update(paint);
}
void update(Paint paint) {
mPaint.set(paint);
}
void draw(Canvas canvas) {
canvas.drawPath(mPath, mPaint);
}
public Path getPath() {
return mPath;
}
/* public DrawOp add(DrawOp value) {
this.x += value.getX();
this.y += value.getY();
return this;
}*/
/*public float getX() {
return x;
}
public float getY() {
return y;
}*/
}
public void fillShapeColor(){
}
// Code for Zoom
/* 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));
invalidate();
return true;
}
}*/
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// float x = detector.getFocusX();
// float y = detector.getFocusY();
lastFocusX = -1;
lastFocusY = -1;
return true;
}
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
focusX = detector.getFocusX();
focusY = detector.getFocusY();
if (lastFocusX == -1)
lastFocusX = focusX;
if (lastFocusY == -1)
lastFocusY = focusY;
mPosX += (focusX - lastFocusX);
mPosY += (focusY - lastFocusY);
Log.v("Hi Zoom", "Factor:" + mScaleFactor);
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.5f, Math.min(mScaleFactor, 2.0f));
lastFocusX = focusX;
lastFocusY = focusY;
invalidate();
return true;
}
}
/* #Override
public Parcelable onSaveInstanceState()
{
System.out.println("save instance");
Bundle bundle = new Bundle();
bundle.putParcelable(EXTRA_STATE, super.onSaveInstanceState());
bundle.putParcelableArrayList(EXTRA_EVENT_LIST, eventList);
return bundle;
}
#Override
public void onRestoreInstanceState(Parcelable state)
{
if (state instanceof Bundle)
{
Bundle bundle = (Bundle) state;
super.onRestoreInstanceState(bundle.getParcelable(EXTRA_STATE));
eventList = bundle.getParcelableArrayList(EXTRA_EVENT_LIST);
if (eventList == null) {
eventList = new ArrayList<MotionEvent>(100);
}
for (MotionEvent event : eventList) {
// performTouchEvent(event);
}
return;
}
super.onRestoreInstanceState(state);
}*/
public void setDrawingFlag(boolean flag) {
// System.out.println("Before Set mFlag " + mFlagDrawing);
this.mFlagDrawing = flag;
// System.out.println("After Set mFlag " + mFlagDrawing);
}
public void moveCanvas(float x, float y) {
float dx = x - mLastTouchX;
float dy = y - mLastTouchY;
// Adjust for zoom factor. Otherwise, the user's finger moving 10 pixels
// at 200% zoom causes the image to slide 20 pixels instead of perfectly
// following the user's touch
dx /= (mScaleFactor * 2);
dy /= (mScaleFactor * 2);
mPosX += dx;
mPosY += dy;
// Log.v(TAG, "moving by " + dx + "," + dy + " mScaleFactor: " +
// mScaleFactor);
}
}
I found mistake and correct it by my self. Below is my code.
public void resetZoom() {
mPanX = mPanY = 0;
final Matrix m = new Matrix();
m.postScale(1f / DENSITY, 1f / DENSITY);
setZoom(m);
invalidate();
}
public void setZoomPosNoInval(float x, float y) {
mPanX = x;
mPanY = y;
}
public void setZoomPos(float x, float y) {
setZoomPosNoInval(x, y);
invalidate();
}
public void setZoomPosNoInval(float[] pos) {
setZoomPosNoInval(pos[0], pos[1]);
}
public void setZoomPos(float[] pos) {
setZoomPosNoInval(pos);
invalidate();
}
public float[] getZoomPos(float[] pos) {
if (pos == null)
pos = new float[2];
pos[0] = mPanX;
pos[1] = mPanY;
return pos;
}
public float getZoomPosX() {
return mPanX;
}
public float getZoomPosY() {
return mPanY;
}
public Matrix getZoom() {
return mZoomMatrix;
}
public Matrix getZoomInv() {
return mZoomMatrixInv;
}
public void setZoom(Matrix m) {
mZoomMatrix.set(m);
mZoomMatrix.invert(mZoomMatrixInv);
}

How to see image in full screen with zoom in / zoom out when touch on image

I have the following imagedetails.xml layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/inLay"
android:layout_width="wrap_content"
android:layout_height="150dp"
android:orientation="horizontal" >
<HorizontalScrollView
android:id="#+id/hsv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:fillViewport="true"
android:measureAllChildren="false"
android:scrollbars="none" >
<LinearLayout
android:id="#+id/innerLay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:id="#+id/controlled_medication"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/as_needed_medication"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:id="#+id/image2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</RelativeLayout>
and for this xml file I have writeen following code:
public class ImageDetails extends Activity {
LinearLayout asthmaActionPlan, controlledMedication, asNeededMedication,
rescueMedication, yourSymtoms, yourTriggers, wheezeRate, peakFlow;
LayoutParams params;
LinearLayout next, prev;
int viewWidth;
GestureDetector gestureDetector = null;
HorizontalScrollView horizontalScrollView;
ArrayList<LinearLayout> layouts;
int parentLeft, parentRight;
int mWidth;
int currPosition, prevPosition;
ImageView image1, image2;
String pid;
private ProgressDialog pDialog;
JSONParser jsonParser = new JSONParser();
private static final String url_detials = "http://www.example.com/details.php";
private static final String TAG_SUCCESS = "success";
private static final String TAG_PRODUCT = "product";
private static final String TAG_PID = "id";
Private static final String TAG_IMAGE1 = "image1";
private static final String TAG_IMAGE2 = "image2";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.productdetails);
image1 = (ImageView) findViewById(R.id.image1);
image2 = (ImageView) findViewById(R.id.image2);
Intent i = getIntent();
pid = i.getStringExtra(TAG_PID);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
horizontalScrollView = (HorizontalScrollView) findViewById(R.id.hsv);
gestureDetector = new GestureDetector(new MyGestureDetector());
controlledMedication = (LinearLayout) findViewById(R.id.controlled_medication);
asNeededMedication = (LinearLayout) findViewById(R.id.as_needed_medication);
Display display = getWindowManager().getDefaultDisplay();
mWidth = display.getWidth(); // deprecated
viewWidth = mWidth;
layouts = new ArrayList<LinearLayout>();
params = new LayoutParams(viewWidth, LayoutParams.WRAP_CONTENT);
controlledMedication.setLayoutParams(params);
asNeededMedication.setLayoutParams(params);
layouts.add(controlledMedication);
layouts.add(asNeededMedication);
horizontalScrollView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
return false;
}
});
new GetDetails().execute();
}
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (e1.getX() < e2.getX()) {
currPosition = getVisibleViews("left");
} else {
currPosition = getVisibleViews("right");
}
horizontalScrollView.smoothScrollTo(layouts.get(currPosition)
.getLeft(), 0);
return true;
}
}
public int getVisibleViews(String direction) {
Rect hitRect = new Rect();
int position = 0;
int rightCounter = 0;
for (int i = 0; i < layouts.size(); i++) {
if (layouts.get(i).getLocalVisibleRect(hitRect)) {
if (direction.equals("left")) {
position = i;
break;
} else if (direction.equals("right")) {
rightCounter++;
position = i;
if (rightCounter == 2)
break;
}
}
}
return position;
}
class GetDetails extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(ImageDetails.this);
pDialog.setMessage("Loading Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
// pDialog.show();
}
#Override
protected String doInBackground(String... arg) {
runOnUiThread(new Runnable() {
public void run() {
int success;
try {
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("id", pid));
JSONObject json = jsonParser.makeHttpRequest(
url_detials, "GET", params);
success = json.getInt(TAG_SUCCESS);
if (success == 1) {
JSONArray productObj = json
.getJSONArray(TAG_PRODUCT);
JSONObject product = productObj.getJSONObject(0);
Bitmap bitmap = null;
Bitmap bitmap2 = null;
try {
// Download Image from URL
InputStream input = new java.net.URL(
product.getString(TAG_IMAGE1))
.openStream();
// Decode Bitmap
bitmap = BitmapFactory.decodeStream(input);
image1.setImageBitmap(bitmap);
// Download Image from URL
InputStream input2 = new java.net.URL(
product.getString(TAG_IMAGE2))
.openStream();
// Decode Bitmap
bitmap2 = BitmapFactory.decodeStream(input2);
image2.setImageBitmap(bitmap2);
} catch (Exception e) {
e.printStackTrace();
}
} else {
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
return null;
}
}
protected void onPostExecute(String file_url) {
// dismiss the dialog once got all details
pDialog.dismiss();
}
}
Now it will give me output in horizontal view where I can change image through gesture touch.
Now When I am select any image than it will open in full screen with zoomin/zoomout option .
I have try following method:
image1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
image1.buildDrawingCache();
Bitmap bitmap = image1.getDrawingCache();
Intent intent = new Intent(getApplicationContext(),
Imagesview.class);
intent.putExtra("BitmapImage", bitmap);
}
});
I am sending image to other activity but it is not open new activity.
I am getting following error log:
FATAL EXCEPTION: main
Process: com.novumlogic.ideal, PID: 18636
java.lang.NullPointerException
at com.novumlogic.ideal.ProductDetails$MyGestureDetector.onFling(ProductDetails.java:213)
at android.view.GestureDetector.onTouchEvent(GestureDetector.java:610)
at com.novumlogic.ideal.ProductDetails$1.onTouch(ProductDetails.java:133)
at android.view.View.dispatchTouchEvent(View.java:7772)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2316)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2013)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2322)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2027)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2322)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2027)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2322)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2027)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2322)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2027)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2322)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2027)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2145)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1577)
at android.app.Activity.dispatchTouchEvent(Activity.java:2508)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2093)
at android.view.View.dispatchPointerEvent(View.java:7973)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4384)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4255)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3801)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3851)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3820)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3927)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3828)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3984)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3801)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3851)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3820)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3828)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3801)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6116)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6096)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6050)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6246)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:138)
at android.os.Looper.loop(Looper.java:150)
at android.app.ActivityThread.main(ActivityThread.java:5333)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
So,how can I show image on full screen with zoom in/out option?
Below class can be used as ImageView for Zoom IN/OUT along with DRAG...
public class TouchImageView extends ImageView {
Matrix matrix;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 3f;
float[] m;
int viewWidth, viewHeight;
static final int CLICK = 3;
float saveScale = 1f;
protected float origWidth, origHeight;
int oldMeasuredWidth, oldMeasuredHeight;
ScaleGestureDetector mScaleDetector;
Context context;
public TouchImageView(Context context) {
super(context);
sharedConstructing(context);
}
public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
sharedConstructing(context);
}
private void stopInterceptEvent()
{
getParent().requestDisallowInterceptTouchEvent(true);
}
private void startInterceptEvent()
{
getParent().requestDisallowInterceptTouchEvent(false);
}
private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix = new Matrix();
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(curr);
start.set(last);
mode = DRAG;
stopInterceptEvent();
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale);
float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale);
matrix.postTranslate(fixTransX, fixTransY);
fixTrans();
last.set(curr.x, curr.y);
float transX = m[Matrix.MTRANS_X];
if((int) (getFixTrans(transX, viewWidth, origWidth * saveScale) + fixTransX) == 0)
startInterceptEvent();
else
stopInterceptEvent();
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
startInterceptEvent();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
}
public void setMaxZoom(float x) {
maxScale = x;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
#Override
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = detector.getScaleFactor();
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight)
matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2);
else
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
fixTrans();
return true;
}
}
void fixTrans() {
matrix.getValues(m);
float transX = m[Matrix.MTRANS_X];
float transY = m[Matrix.MTRANS_Y];
float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale);
if (fixTransX != 0 || fixTransY != 0)
matrix.postTranslate(fixTransX, fixTransY);
}
float getFixTrans(float trans, float viewSize, float contentSize) {
float minTrans, maxTrans;
if (contentSize <= viewSize) {
minTrans = 0;
maxTrans = viewSize - contentSize;
} else {
minTrans = viewSize - contentSize;
maxTrans = 0;
}
if (trans < minTrans)
return -trans + minTrans;
if (trans > maxTrans)
return -trans + maxTrans;
return 0;
}
float getFixDragTrans(float delta, float viewSize, float contentSize) {
if (contentSize <= viewSize) {
return 0;
}
return delta;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = MeasureSpec.getSize(widthMeasureSpec);
viewHeight = MeasureSpec.getSize(heightMeasureSpec);
//
// Rescales image on rotation
//
if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
|| viewWidth == 0 || viewHeight == 0)
return;
oldMeasuredHeight = viewHeight;
oldMeasuredWidth = viewWidth;
if (saveScale == 1) {
//Fit to screen.
float scale;
Drawable drawable = getDrawable();
if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0)
return;
int bmWidth = drawable.getIntrinsicWidth();
int bmHeight = drawable.getIntrinsicHeight();
Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);
float scaleX = (float) viewWidth / (float) bmWidth;
float scaleY = (float) viewHeight / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
// Center the image
float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = viewWidth - 2 * redundantXSpace;
origHeight = viewHeight - 2 * redundantYSpace;
setImageMatrix(matrix);
}
fixTrans();
}
}
Replace your ImageView
<ImageView
android:id="#+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
with this one:
<com.pkg.TouchImageView
android:id="#+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
You can use RecyclingImageView as a super class here for your app efficiency. It will also work with Android native ImageView
I hope this might help you.
Android doesn't support out of the box zooming functionality for imageViews. So you must do some custom implementation to scale(Zoom In/Zoom out) imageView (That what you did). Or you can use third-party libs to lift your heavy work. They can handle all your scenarios. I usually prefer Chris Bane's Photoview.
public class ZoomableImageView extends View {
private static final String TAG = "ZoomableImageView"; float trans=80;
public static Bitmap imgBitmap = null;
Boolean zom=false;
private static WeakReference<Context> mContext;
//Matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
PointF start = new PointF();
//We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
//For animating stuff
float easing = 0.2f;
boolean isAnimating = false;int flag=0;
float scaleDampingFactor = 0.5f;
private WeakReference<Bitmap> resizedBitmap,mBitmap;
//For pinch and zoom
float oldDist = 1f;
PointF mid = new PointF();Bitmap bms;
private Handler mHandler = new Handler();
float minScale;
float maxScale = 8.0f;
public static int index=1000;
float wpRadius = 25.0f;
float wpInnerRadius = 20.0f;
public static final int DEFAULT_SCALE_FIT_INSIDE = 0;
public static final int DEFAULT_SCALE_ORIGINAL = 1;
public int getDefaultScale() {
return defaultScale;
}
public void setDefaultScale(int defaultScale) {
this.defaultScale = defaultScale;
}
public ZoomableImageView(Context context) {
super(context);
con=context;
setFocusable(true);
setFocusableInTouchMode(true);
File file = new File(HomePage.sdfile + "/" + index+".jpg");
Options options = new BitmapFactory.Options();
try{
options.inScaled = false;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
imgBitmap=decodeFile(file);
}
catch(OutOfMemoryError e){
System.out.println("out of memory");
flag=1;
System.out.println("clearing bitmap????????????");
if (imgBitmap!=null) {
this.setBackgroundResource(0);
this.clearAnimation();
imgBitmap.recycle();
imgBitmap = null;}
}
screenDensity = context.getResources().getDisplayMetrics().density;
initPaints();
gestureDetector = new GestureDetector(new MyGestureDetector());
}
public ZoomableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println("zoomableimageview");
screenDensity = context.getResources().getDisplayMetrics().density;
initPaints();
gestureDetector = new GestureDetector(new MyGestureDetector());
defaultScale = ZoomableImageView.DEFAULT_SCALE_FIT_INSIDE;
}
private void initPaints() {
background = new Paint();
System.out.println("initPaints");
}
#Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
System.out.println("onsizechanged");
//Reset the width and height. Will draw bitmap and change
containerWidth = width;
containerHeight = height;
if(imgBitmap != null) {
int imgHeight = imgBitmap.getHeight();
int imgWidth = imgBitmap.getWidth();
float scale;
int initX = 0;
int initY = 0;
if(defaultScale == ZoomableImageView.DEFAULT_SCALE_FIT_INSIDE) {
if(imgWidth > containerWidth) {
scale = (float)containerWidth / imgWidth;
float newHeight = imgHeight * scale;
initY = (containerHeight - (int)newHeight)/2;
matrix.setScale(scale, scale);
matrix.postTranslate(0, initY);
System.out.println("scale"+scale);
}
else {
scale = (float)containerHeight / imgHeight;
float newWidth = imgWidth * scale;
initX = (containerWidth - (int)newWidth)/2;
matrix.setScale(scale, scale);
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = scale;
minScale = scale;
System.out.println("scale"+scale);
}
else {
if(imgWidth > containerWidth) {
initY = (containerHeight - (int)imgHeight)/2;
matrix.postTranslate(0, initY);
}
else {
initX = (containerWidth - (int)imgWidth)/2;
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = 1.0f;
minScale = 1.0f;
}
System.out.println("currentscale"+currentScale);
System.out.println("minscale"+minScale);
invalidate();
}
}
#Override
protected void onDraw(Canvas canvas) {
System.out.println("ondraw");
if(imgBitmap != null && canvas != null)
{
canvas.drawBitmap(imgBitmap, matrix, background);
System.out.println("image not null---------------------");
}
if(flag==1){
System.out.println("image null*************************");
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
con.startActivity(intent);
System.exit(0);
}
}
//Checks and sets the target image x and y co-ordinates if out of bounds
private void checkImageConstraints() {
System.out.println("checkimageconstans");
if(imgBitmap == null) {
return;
}
float[] mvals = new float[9];
matrix.getValues(mvals);
currentScale = mvals[0];
if(currentScale < minScale) {
float deltaScale = minScale / currentScale;
float px = containerWidth/2;
float py = containerHeight/2;
matrix.postScale(deltaScale, deltaScale, px, py);
invalidate();
}
matrix.getValues(mvals);
currentScale = mvals[0];
curX = mvals[2];
curY = mvals[5];
int rangeLimitX = containerWidth - (int)(imgBitmap.getWidth() * currentScale);
int rangeLimitY = containerHeight - (int)(imgBitmap.getHeight() * currentScale);
boolean toMoveX = false;
boolean toMoveY = false;
if(rangeLimitX < 0) {
if(curX > 0) {
targetX = 0;
toMoveX = true;
}
else if(curX < rangeLimitX) {
targetX = rangeLimitX;
toMoveX = true;
}
}
else {
targetX = rangeLimitX / 2;
toMoveX = true;
}
if(rangeLimitY < 0) {
if(curY > 0) {
targetY = 0;
toMoveY = true;
}
else if(curY < rangeLimitY) {
targetY = rangeLimitY;
toMoveY = true;
}
}
else {
targetY = rangeLimitY / 2;
toMoveY = true;
}
if(toMoveX == true || toMoveY == true) {
if(toMoveY == false) {
targetY = curY;
}
if(toMoveX == false) {
targetX = curX;
}
//Disable touch event actions
isAnimating = true;
//Initialize timer
mHandler.removeCallbacks(mUpdateImagePositionTask);
mHandler.postDelayed(mUpdateImagePositionTask, 100);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("onTouch");
flag=0;
if(gestureDetector.onTouchEvent(event)) {
return true;
}
if(isAnimating == true) {
return true;
}
//Handle touch events here
float[] mvals = new float[9];
switch(event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if(isAnimating == false) {
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if(oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
matrix.getValues(mvals);
curX = mvals[2];
curY = mvals[5];
currentScale = mvals[0];
if(isAnimating == false) {
checkImageConstraints();
}
break;
case MotionEvent.ACTION_MOVE:
if(mode == DRAG && isAnimating == false) {
matrix.set(savedMatrix);
float diffX = event.getX() - start.x;
float diffY = event.getY() - start.y;
matrix.postTranslate(diffX, diffY);
matrix.getValues(mvals);
curX = mvals[2];
curY = mvals[5];
currentScale = mvals[0];
}
else if(mode == ZOOM && isAnimating == false) {
System.out.println("for zooming");
zom=true;
float newDist = spacing(event);
if(newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.getValues(mvals);
currentScale = mvals[0];
if(currentScale * scale <= minScale) {
matrix.postScale(minScale/currentScale, minScale/currentScale, mid.x, mid.y);
}
else if(currentScale * scale >= maxScale) {
matrix.postScale(maxScale/currentScale, maxScale/currentScale, mid.x, mid.y);
}
else {
matrix.postScale(scale, scale, mid.x, mid.y);
}
matrix.getValues(mvals);
curX = mvals[2];
curY = mvals[5];
currentScale = mvals[0];
trans=scale;
}
}
break;
}
//Calculate the transformations and then invalidate
invalidate();
return true;
}
private float spacing(MotionEvent event) {
System.out.println("spacing");
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
System.out.println("midpoint");
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x/2, y/2);
}
public void setImageBitmap(Bitmap b) {
System.out.println("setImageBitmap");
if(b != null) {
imgBitmap = b;
containerWidth = getWidth();
containerHeight = getHeight();
int imgHeight = imgBitmap.getHeight();
int imgWidth = imgBitmap.getWidth();
float scale;
int initX = 0;
int initY = 0;
matrix.reset();
if(defaultScale == ZoomableImageView.DEFAULT_SCALE_FIT_INSIDE) {
if(imgWidth > containerWidth) {
scale = (float)containerWidth / imgWidth;
float newHeight = imgHeight * scale;
initY = (containerHeight - (int)newHeight)/2;
matrix.setScale(scale, scale);
matrix.postTranslate(0, initY);
}
else {
scale = (float)containerHeight / imgHeight;
float newWidth = imgWidth * scale;
initX = (containerWidth - (int)newWidth)/2;
matrix.setScale(scale, scale);
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = scale;
minScale = scale;
}
else {
if(imgWidth > containerWidth) {
initX = 0;
if(imgHeight > containerHeight) {
initY = 0;
}
else {
initY = (containerHeight - (int)imgHeight)/2;
}
matrix.postTranslate(0, initY);
}
else {
initX = (containerWidth - (int)imgWidth)/2;
if(imgHeight > containerHeight) {
initY = 0;
}
else {
initY = (containerHeight - (int)imgHeight)/2;
}
matrix.postTranslate(initX, 0);
}
curX = initX;
curY = initY;
currentScale = .5f;
minScale = .5f;
}
invalidate();
}
else {
Log.d(TAG, "bitmap is null");
}
}
public Bitmap getPhotoBitmap() {
System.out.println("getphotobitmap");
return imgBitmap;
}
private Runnable mUpdateImagePositionTask = new Runnable() {
public void run() {
//zoomout();
if(zom==true && trans<1.0f)
{PageCurlView.zoom=0;
Intent i = new Intent();
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setClass(getContext(), StandaloneExample.class);
getContext().startActivity(i);
zoomout();
if(imgBitmap!=null){
imgBitmap.recycle();
imgBitmap = null;}
//
try {
this.finalize();
} catch (Throwable e) {
// TODO Auto-generated catch block
System.out.println("finalizer problem");
e.printStackTrace();
}
//
}
System.out.println("run");
float[] mvals;
if(Math.abs(targetX - curX) < 5 && Math.abs(targetY - curY) < 5) {
isAnimating = false;
mHandler.removeCallbacks(mUpdateImagePositionTask);
mvals = new float[9];
matrix.getValues(mvals);
currentScale = mvals[0];
curX = mvals[2];
curY = mvals[5];
//Set the image parameters and invalidate display
float diffX = (targetX - curX);
float diffY = (targetY - curY);
matrix.postTranslate(diffX, diffY);
}
else {
isAnimating = true;
mvals = new float[9];
matrix.getValues(mvals);
currentScale = mvals[0];
curX = mvals[2];
curY = mvals[5];
//Set the image parameters and invalidate display
float diffX = (targetX - curX) * 0.3f;
float diffY = (targetY - curY) * 0.3f;
matrix.postTranslate(diffX, diffY);
mHandler.postDelayed(this, 25);
}
invalidate();
}
};
private Runnable mUpdateImageScale = new Runnable() {
public void run() {
System.out.println("run2");
float transitionalRatio = targetScale / currentScale;
float dx;
if(Math.abs(transitionalRatio - 1) > 0.05) {
isAnimating = true;
if(targetScale > currentScale) {
dx = transitionalRatio - 1;
scaleChange = 1 + dx * 0.2f;
currentScale *= scaleChange;
if(currentScale > targetScale) {
currentScale = currentScale / scaleChange;
scaleChange = 1;
}
}
else {
dx = 1 - transitionalRatio;
scaleChange = 1 - dx * 0.5f;
currentScale *= scaleChange;
if(currentScale < targetScale) {
currentScale = currentScale / scaleChange;
scaleChange = 1;
}
}
if(scaleChange != 1) {
matrix.postScale(scaleChange, scaleChange, targetScaleX, targetScaleY);
mHandler.postDelayed(mUpdateImageScale, 15);
invalidate();
}
else {
isAnimating = false;
scaleChange = 1;
matrix.postScale(targetScale/currentScale, targetScale/currentScale, targetScaleX, targetScaleY);
currentScale = targetScale;
mHandler.removeCallbacks(mUpdateImageScale);
invalidate();
checkImageConstraints();
}
}
else {
isAnimating = false;
scaleChange = 1;
matrix.postScale(targetScale/currentScale, targetScale/currentScale, targetScaleX, targetScaleY);
currentScale = targetScale;
mHandler.removeCallbacks(mUpdateImageScale);
invalidate();
checkImageConstraints();
}
}
};
/** Show an event in the LogCat view, for debugging */
private void dumpEvent(MotionEvent event) {
System.out.println("dumpevent");
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
}
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onDoubleTap(MotionEvent event) {
System.out.println("simpleOnGestureListener");
if(isAnimating == true) {
return true;
}
scaleChange = 1;
isAnimating = true;
targetScaleX = event.getX();
targetScaleY = event.getY();
if(Math.abs(currentScale - maxScale) > 0.1) {
targetScale = maxScale;
}
else {
targetScale = minScale;
}
targetRatio = targetScale / currentScale;
mHandler.removeCallbacks(mUpdateImageScale);
mHandler.post(mUpdateImageScale);
return true;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
System.out.println("onfling");
return super.onFling(e1, e2, velocityX, velocityY);
}
#Override
public boolean onDown(MotionEvent e) {
System.out.println("ondown");
return false;
}
}
public Bitmap decodeFile(File f) {
try {
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
o.inDither=false; //Disable Dithering mode
o.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
o.inInputShareable=true;
o.inPreferredConfig = Bitmap.Config.ARGB_8888;
//Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
o.inTempStorage=new byte[16*1024];
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// Find the correct scale value. It should be the power of 2.
int REQUIRED_SIZE = 300;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
if(REQUIRED_SIZE > width_tmp)
REQUIRED_SIZE = width_tmp;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
System.out.println(scale+"______________________________-");
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inDither=false;
o2.inScaled = false;
o2.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
o2.inInputShareable=true;
//Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
o2.inTempStorage=new byte[24*1024];
o2.inSampleSize = 2;
o2.outWidth = width_tmp;
o2.outHeight = height_tmp;
o2.inPreferredConfig = Bitmap.Config.ARGB_8888;
try {
BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(o2,true);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
o2.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(new FileInputStream(f), null,
o2);
}
catch (FileNotFoundException e) {
System.out.println("file not found");
}
return null;
}
// #Override
//protected void onDetachedFromWindow() {
// // TODO Auto-generated method stub
// System.out.println("ondetatched from wind");
// super.onDetachedFromWindow();
// if (imgBitmap != null) {
// imgBitmap.recycle();
// imgBitmap=null;}
//
//}
public void zoomout(){
if(zom==true && trans<1.0f)
{PageCurlView.zoom=0;
// Intent i = new Intent();
// i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// i.setClass(getContext(), StandaloneExample.class);
// getContext().startActivity(i);
if(imgBitmap!=null){
this.setBackgroundResource(0);
this.clearAnimation();
this.setBackgroundResource(0);
this.clearAnimation();
imgBitmap.recycle();
imgBitmap = null;}
//
try {
this.finalize();
} catch (Throwable e) {
// TODO Auto-generated catch block
System.out.println("finalizer problem");
e.printStackTrace();
}
}
}
}
you can include this class to your package and replace in your xml file with

Dynamically add edittext apply pinch zoom, rotate and drag

can anyone please help me, how to implement pinch zoom, rotate and drag on dynamic edittext android. i have tried many things but not getting proper output. Please tell m easy way to implement this.
this is my activity.
public class MainActivity extends Activity implements OnRotationGestureListener {
RelativeLayout container;
TextView curEt;
private float oldDist = 1f;
int count = 0;
private PointF mid = new PointF();
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private float[] lastEvent = null;
private int mode = NONE;
public int firstClick;
public int secClick;
public int offset_x;
public int offset_y;
private PointF start = new PointF();
private float degrees, prevDegrees;
private RotationGestureDetector mRotationDetector;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_editable_area);
container = (RelativeLayout) findViewById(R.id.container);
mRotationDetector = new RotationGestureDetector(this);
curEt = new EditText(this);
container.setOnTouchListener(new MyTouch());
}
class MyTouch implements OnTouchListener {
private static final float MAX_FONT_SIZE = 100;
private static final float MIN_FONT_SIZE = 10;
#Override
public boolean onTouch(View v, MotionEvent event) {
mRotationDetector.onTouchEvent(event);
System.out.println();
if (container == v) {
if (MotionEvent.ACTION_DOWN == event.getAction()) {
createET(event);
}
} else {
curEt = (EditText) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
start.set(event.getX(), event.getY());
offset_x = (int) event.getX();
offset_y = (int) event.getY();
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
midPoint(mid, event);
mode = ZOOM;
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
// d = rotation(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
prevDegrees = degrees;
mode = NONE;
// lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
// curEt.setX(event.getRawX() - 40);
// curEt.setY(event.getRawY() - 150);
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
float scale = newDist / oldDist;
if (scale > 1) {
scale = 1.1f;
} else if (scale < 1) {
scale = 0.95f;
}
float currentSize = curEt.getTextSize() * scale;
if ((currentSize < MAX_FONT_SIZE && currentSize > MIN_FONT_SIZE)
|| (currentSize >= MAX_FONT_SIZE && scale < 1)
|| (currentSize <= MIN_FONT_SIZE && scale > 1)) {
curEt.setTextSize(TypedValue.COMPLEX_UNIT_PX,
currentSize);
}
}
if (lastEvent != null) {
// float newRot = rotation(event);
// float r = newRot - d;
if (degrees < 180 && degrees > -180) {
curEt.animate().rotationBy(-degrees);
curEt.setRotation(-degrees);
}
// RotateAnimation an = new RotateAnimation(0.0f,
// degrees, 0, 0);
// RotateAnimation anim = new RotateAnimation(0,
// degrees,
// Animation.RELATIVE_TO_SELF, 0f,
// Animation.RELATIVE_TO_SELF,0f);
// //degrees = (degrees + 30) % 360;
}
}
break;
}
}
return false;
}
}
private void createET(MotionEvent event) {
EditText et = new EditText(MainActivity.this);
curEt = et;
curEt.setHint("EditText");
curEt.setTag(et.getId());
curEt.setX(event.getX());
curEt.setFocusable(false);
curEt.setY(event.getY());
curEt.setSingleLine(true);
curEt.setOnTouchListener(new MyTouch());
container.addView(et);
}
/* Determine the space between the first two fingers */
private float spacing(MotionEvent event) {
return (float) (Math.pow((event.getX(1) - event.getX(0)), 2) + Math
.pow((event.getY(1) - event.getY(0)), 2));
}
/* 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);
}
#Override
public void OnRotation(RotationGestureDetector rotationDetector) {
degrees = rotationDetector.getAngle();
System.out.println(degrees);
}
/* Calculate the degree to be rotated by. */
// private float rotation(MotionEvent event) {
// float x = event.getX(0) - event.getX(1);
// float y = event.getY(0) - event.getY(1);
// DisplayMetrics displaymetrics = new DisplayMetrics();
// getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
// int height = displaymetrics.heightPixels;
// int width = displaymetrics.widthPixels;
// double delta_x = x - (width) /2;
// double delta_y = (height) /2 - y;
// double radians = Math.atan2(delta_y, delta_x);
// return (float) Math.toDegrees(radians);
// }
}
and XML Layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
please help me with this. if i try to rotate it gets flickering effect.

Android ImageView Scaling and translating issue

I’m developing an android application (API 19 4.4) and I encounter some issue with ImageViews.
I have a SurfaceView, in which I dynamically add ImageViews which I want to react to touch events.
On so far, I have managed to make the ImageView move and scale smoothly but I have an annoying behavior.
When I scale down the image to a certain limit (I would say half the original size) and I try to move it, the image flicker.
After a short analysis, it seems that it’s switching its position symmetrically around the finger point on the screen, cumulating distance, and finally gets out of sight (all that happens very fast ( < 1s).
I think I am missing something with the relative value of the touch event to the ImageView/SurfaceView, but I’m a quite a noob and I’m stucked…
Here is my code
public class MyImageView extends ImageView {
private ScaleGestureDetector mScaleDetector ;
private static final int MAX_SIZE = 1024;
private static final String TAG = "MyImageView";
PointF DownPT = new PointF(); // Record Mouse Position When Pressed Down
PointF StartPT = new PointF(); // Record Start Position of 'img'
public MyImageView(Context context) {
super(context);
mScaleDetector = new ScaleGestureDetector(context,new MySimpleOnScaleGestureListener());
setBackgroundColor(Color.RED);
setScaleType(ScaleType.MATRIX);
setAdjustViewBounds(true);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(-MAX_SIZE, -MAX_SIZE, -MAX_SIZE, -MAX_SIZE);
this.setLayoutParams(lp);
this.setX(MAX_SIZE);
this.setY(MAX_SIZE);
}
int firstPointerID;
boolean inScaling=false;
#Override
public boolean onTouchEvent(MotionEvent event) {
// get pointer index from the event object
int pointerIndex = event.getActionIndex();
// get pointer ID
int pointerId = event.getPointerId(pointerIndex);
//First send event to scale detector to find out, if it's a scale
boolean res = mScaleDetector.onTouchEvent(event);
if (!mScaleDetector.isInProgress()) {
int eid = event.getAction();
switch (eid & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_MOVE :
if(pointerId == firstPointerID) {
PointF mv = new PointF( (int)(event.getX() - DownPT.x), (int)( event.getY() - DownPT.y));
this.setX((int)(StartPT.x+mv.x));
this.setY((int)(StartPT.y+mv.y));
StartPT = new PointF( this.getX(), this.getY() );
}
break;
case MotionEvent.ACTION_DOWN : {
firstPointerID = pointerId;
DownPT.x = (int) event.getX();
DownPT.y = (int) event.getY();
StartPT = new PointF( this.getX(), this.getY() );
break;
}
case MotionEvent.ACTION_POINTER_DOWN: {
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL: {
firstPointerID = -1;
break;
}
default :
break;
}
return true;
}
return true;
}
public boolean onScaling(ScaleGestureDetector detector) {
this.setScaleX(this.getScaleX()*detector.getScaleFactor());
this.setScaleY(this.getScaleY()*detector.getScaleFactor());
invalidate();
return true;
}
private class MySimpleOnScaleGestureListener extends SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
return onScaling(detector);
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
Log.d(TAG, "onScaleBegin");
return true;
}
#Override
public void onScaleEnd(ScaleGestureDetector arg0) {
Log.d(TAG, "onScaleEnd");
}
}
}
I have also another questions about rotations. How should I implement this?
Could I use the ScalegestureDetector in some way or have I to make this works in the view touch event? I would like to be able to scale and rotate in the same gesture (and move in another).
Thank for helping me, I would really appreciate!
Sorry for my english
this is a working example of two fingers move/scale/rotate (note: the code is quite short due to smart detector used - see MatrixGestureDetector):
class ViewPort extends View {
List<Layer> layers = new LinkedList<Layer>();
int[] ids = {R.drawable.layer0, R.drawable.layer1, R.drawable.layer2};
public ViewPort(Context context) {
super(context);
Resources res = getResources();
for (int i = 0; i < ids.length; i++) {
Layer l = new Layer(context, this, BitmapFactory.decodeResource(res, ids[i]));
layers.add(l);
}
}
#Override
protected void onDraw(Canvas canvas) {
for (Layer l : layers) {
l.draw(canvas);
}
}
private Layer target;
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
target = null;
for (int i = layers.size() - 1; i >= 0; i--) {
Layer l = layers.get(i);
if (l.contains(event)) {
target = l;
layers.remove(l);
layers.add(l);
invalidate();
break;
}
}
}
if (target == null) {
return false;
}
return target.onTouchEvent(event);
}
}
class Layer implements MatrixGestureDetector.OnMatrixChangeListener {
Matrix matrix = new Matrix();
Matrix inverse = new Matrix();
RectF bounds;
View parent;
Bitmap bitmap;
MatrixGestureDetector mgd = new MatrixGestureDetector(matrix, this);
public Layer(Context ctx, View p, Bitmap b) {
parent = p;
bitmap = b;
bounds = new RectF(0, 0, b.getWidth(), b.getHeight());
matrix.postTranslate(50 + (float) Math.random() * 50, 50 + (float) Math.random() * 50);
}
public boolean contains(MotionEvent event) {
matrix.invert(inverse);
float[] pts = {event.getX(), event.getY()};
inverse.mapPoints(pts);
if (!bounds.contains(pts[0], pts[1])) {
return false;
}
return Color.alpha(bitmap.getPixel((int) pts[0], (int) pts[1])) != 0;
}
public boolean onTouchEvent(MotionEvent event) {
mgd.onTouchEvent(event);
return true;
}
#Override
public void onChange(Matrix matrix) {
parent.invalidate();
}
public void draw(Canvas canvas) {
canvas.drawBitmap(bitmap, matrix, null);
}
}
class MatrixGestureDetector {
private static final String TAG = "MatrixGestureDetector";
private int ptpIdx = 0;
private Matrix mTempMatrix = new Matrix();
private Matrix mMatrix;
private OnMatrixChangeListener mListener;
private float[] mSrc = new float[4];
private float[] mDst = new float[4];
private int mCount;
interface OnMatrixChangeListener {
void onChange(Matrix matrix);
}
public MatrixGestureDetector(Matrix matrix, MatrixGestureDetector.OnMatrixChangeListener listener) {
this.mMatrix = matrix;
this.mListener = listener;
}
public void onTouchEvent(MotionEvent event) {
if (event.getPointerCount() > 2) {
return;
}
int action = event.getActionMasked();
int index = event.getActionIndex();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
int idx = index * 2;
mSrc[idx] = event.getX(index);
mSrc[idx + 1] = event.getY(index);
mCount++;
ptpIdx = 0;
break;
case MotionEvent.ACTION_MOVE:
for (int i = 0; i < mCount; i++) {
idx = ptpIdx + i * 2;
mDst[idx] = event.getX(i);
mDst[idx + 1] = event.getY(i);
}
mTempMatrix.setPolyToPoly(mSrc, ptpIdx, mDst, ptpIdx, mCount);
mMatrix.postConcat(mTempMatrix);
if(mListener != null) {
mListener.onChange(mMatrix);
}
System.arraycopy(mDst, 0, mSrc, 0, mDst.length);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerId(index) == 0) ptpIdx = 2;
mCount--;
break;
}
}
}
I tried to implementation of multiple touch on view not on bitmap using matrix, now i success. Now i think it will helpful to you for individual gesture for multiple image. Try it, it work best for me.
public class MultiTouchImageView extends ImageView implements OnTouchListener{
float[] lastEvent = null;
float d = 0f;
float newRot = 0f;
public static String fileNAME;
public static int framePos = 0;
//private ImageView view;
private boolean isZoomAndRotate;
private boolean isOutSide;
// We can be in one of these 3 states
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private PointF start = new PointF();
private PointF mid = new PointF();
float oldDist = 1f;
public MultiTouchImageView(Context context) {
super(context);
}
public MultiTouchImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MultiTouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#SuppressWarnings("deprecation")
#Override
public boolean onTouch(View v, MotionEvent event) {
//view = (ImageView) v;
bringToFront();
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
//savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP:
isZoomAndRotate = false;
case MotionEvent.ACTION_OUTSIDE:
isOutSide = true;
mode = NONE;
lastEvent = null;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if(!isOutSide){
if (mode == DRAG && !isZoomAndRotate) {
isZoomAndRotate = false;
setTranslationX((event.getX() - start.x) + getTranslationX());
setTranslationY((event.getY() - start.y) + getTranslationY());
} else if (mode == ZOOM && event.getPointerCount() == 2) {
isZoomAndRotate = true;
boolean isZoom = false;
if(!isRotate(event)){
float newDist = spacing(event);
if (newDist > 10f) {
float scale = newDist / oldDist * getScaleX();
setScaleX(scale);
setScaleY(scale);
isZoom = true;
}
}
else if(!isZoom){
newRot = rotation(event);
setRotation((float)(getRotation() + (newRot - d)));
}
}
}
break;
}
new GestureDetector(new MyGestureDectore());
Constants.currentSticker = this;
return true;
}
private class MyGestureDectore extends GestureDetector.SimpleOnGestureListener{
#Override
public boolean onDoubleTap(MotionEvent e) {
bringToFront();
return false;
}
#Override
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
}
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
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);
}
private boolean isRotate(MotionEvent event){
int dx1 = (int) (event.getX(0) - lastEvent[0]);
int dy1 = (int) (event.getY(0) - lastEvent[2]);
int dx2 = (int) (event.getX(1) - lastEvent[1]);
int dy2 = (int) (event.getY(1) - lastEvent[3]);
Log.d("dx1 ", ""+ dx1);
Log.d("dx2 ", "" + dx2);
Log.d("dy1 ", "" + dy1);
Log.d("dy2 ", "" + dy2);
//pointer 1
if(Math.abs(dx1) > Math.abs(dy1) && Math.abs(dx2) > Math.abs(dy2)) {
if(dx1 >= 2.0 && dx2 <= -2.0){
Log.d("first pointer ", "right");
return true;
}
else if(dx1 <= -2.0 && dx2 >= 2.0){
Log.d("first pointer ", "left");
return true;
}
}
else {
if(dy1 >= 2.0 && dy2 <= -2.0){
Log.d("seccond pointer ", "top");
return true;
}
else if(dy1 <= -2.0 && dy2 >= 2.0){
Log.d("second pointer ", "bottom");
return true;
}
}
return false;
}
}
I finally use this (spacing is used to calculated the distance between two fingers), I offset the imageview after scaling to keep it centered, works fine for now :
float newDist = spacing(event);
float scale = newDist / oldDist;
int oldH =getLayoutParams().height;
int oldW =getLayoutParams().width;
int newH =(int) (getLayoutParams().height*scale);
int newW =(int) (getLayoutParams().width*scale);
if(newH<MAX_SIZE && newW<MAX_SIZE){
//scale the height and width of the view
getLayoutParams().height = newH;
getLayoutParams().width = newW;
//calculate the X and Y offset to apply after scaling to keep the image centered
int xOffset = (int)(getLayoutParams().height - oldH)/2;
int yOffset = (int)(getLayoutParams().width - oldW)/2;
setX(getX()-xOffset);
setY(getY()-yOffset);
requestLayout();
setAdjustViewBounds(true);
oldDist=newDist;
All these examples had a glitchy gesture support because of scaleType was set to matrix. When I tried to zoom, I was not able to keep the image in center and control the amount of zoom. So I did some study and wrote a small, easy but very pleasing code for this: https://stackoverflow.com/a/65697376/13339685

Paint View Zoom with Image problem

anyone knows how to zoom paint view with image correctly?
At following code, I used canvas zoom in order to zoom paint view with image including using setImageMatrix().
But problem arised, that is entire screen became to zoom in/out but not paint view and image only.
So If anyone knows this issue, reply plz.
PaintScreen.java
public class PaintScreen extends Activity implements ColorPickerDialog.OnColorChangedListener{
Context mContext;
private Paint mPaint;
MaskFilter mEmboss;
MaskFilter mBlur;
private ImageView mImageView;
private LinearLayout mPaintBaseLayout;
private FrameLayout mTouchBaseLayout;
private PaintView mPaintView;
private int[] mPixels;
private Bitmap mBitmapImage;
private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
MultiTouchListener multiTouchLitener = new MultiTouchListener(this);
private static final String TAG = "Touch";
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
Matrix savedMatrix2 = new Matrix();
private int WIDTH = 0;
private int HEIGHT = 1;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int POINT2 = 2;
static final int ZOOM = 3;
int mode = NONE;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
float newDist;
float distanceOffset = 50f;
float minOffset = 50f;
float maxOffset = 10000f;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.paint_mode1_paint);
this.initialize();
this.PaintSet();
}
private void initialize()
{
mPaintBaseLayout = (LinearLayout) findViewById(R.id.paint_paint_base_layout);
mTouchBaseLayout = (FrameLayout) findViewById(R.id.paint_touch_base_layout);
mContext = this;
mPaint = new Paint();
mPaintView = new PaintView(mContext);
mPaintView.setBackgroundColor(Color.TRANSPARENT);
mPaintBaseLayout.addView(mPaintView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
mPaintBaseLayout.setBackgroundColor(Color.TRANSPARENT);
mPaintView.setScaleType(ScaleType.MATRIX);
mPaintView.setMPaint(mPaint);
Intent intent = getIntent();
Bundle itstr = intent.getExtras();
String imagePath = itstr.getString("image_path");
Drawable d = Drawable.createFromPath(imagePath);
mPaintView.setBackgroundDrawable(d);
mPaintView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
dumpEvent(event);
PaintView view = (PaintView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
start.set(event.getX(), event.getY());
savedMatrix.set(matrix);
midPoint(mid, event);
mode = POINT2;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
distanceOffset = minOffset;
break;
case MotionEvent.ACTION_MOVE:
if (mode == POINT2)
{
newDist = spacing(event);
if (newDist - oldDist > 5f
|| newDist - oldDist < -5f) {
mode = ZOOM;
} else {
start.set(event.getX(), event.getY());
mode = DRAG;
}
} else
if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
}
else if (mode == ZOOM) {
newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
} else {
view.onTouchEvent(event);
}
break;
}
matrixTurning(matrix, view);
view.setImageMatrix(matrix);
view.cMatrix(matrix);
return true;
}
});
}
/** Show an event in the LogCat view, for debugging */
private static void dumpEvent(MotionEvent event) {
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",
"POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid ").append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
Log.d(TAG, sb.toString());
}
/** Determine the space between the first two fingers */
private static float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private static 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);
}
private void matrixTurning(Matrix matrix, ImageView view){
float[] value = new float[9];
matrix.getValues(value);
float[] savedValue = new float[9];
savedMatrix2.getValues(savedValue);
// view size
int width = view.getWidth();
int height = view.getHeight();
//image size
Drawable d = view.getDrawable();
if(d == null) return;
int imageWidth = d.getIntrinsicWidth();
int imageHeight = d.getIntrinsicHeight();
int scaleWidth = (int)(imageWidth*value[0]);
int scaleHeight = (int)(imageHeight*value[0]);
if(value[2] < width - scaleWidth) value[2] = width - scaleWidth;
if(value[5] < height - scaleHeight) value[5] = height - scaleHeight;
if(value[2] > 0) value[2] = 0;
if(value[5] > 0) value[5] = 0;
if(value[0] > 10 || value[4] > 10){
value[0] = savedValue[0];
value[4] = savedValue[4];
value[2] = savedValue[2];
value[5] = savedValue[5];
}
if(imageWidth > width || imageHeight > height){
if(scaleWidth < width && scaleHeight < height){
int target = WIDTH;
if(imageWidth < imageHeight) target = HEIGHT;
if(target == WIDTH) value[0] = value[4] = (float)width/imageWidth;
if(target == HEIGHT) value[0] = value[4] = (float)height/imageHeight;
scaleWidth = (int)(imageWidth*value[0]);
scaleHeight = (int)(imageHeight*value[4]);
if(scaleWidth == width) value[0] = value[4] = (float)width/imageWidth;
if(scaleHeight == height) value[0] = value[4] = (float)height/imageHeight;
}
}else{
if(value[0] < 1) value[0] = 1;
if(value[4] < 1) value[4] = 1;
}
scaleWidth = (int)(imageWidth*value[0]);
scaleHeight = (int)(imageHeight*value[4]);
if(scaleWidth < width){
value[2] = (float)width/2-(float)scaleWidth/2;
}
if(scaleHeight < height){
value[5] = (float)height/2-(float)scaleHeight/2;
}
matrix.setValues(value);
savedMatrix2.set(matrix);
}
public void PaintSet(){
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(24);
getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(24, BlurMaskFilter.Blur.NORMAL);
}
public void colorChanged(int color) {
mPaint.setColor(color);
}
}
PaintView.java
public class PaintView extends ImageView {
private Context mContext;
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private Bitmap testBitmap;
private Canvas mCanvas;
private Canvas tCanvas;
private Path mPath;
private Paint mBitmapPaint;
// onDraw
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
// onTouch
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
public PaintView(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
mContext = context;
mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
//mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.drawColor(0xFFAAAAAA);
super.onDraw(canvas);
mCanvas = canvas;
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
public void setMPaint(Paint paint) {
mPaint = paint;
}
private void touchStart(float x, float y) {
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);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
Log.d("PaintView", "ev ->" + event.getAction());
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;
}
public void cMatrix(Matrix matrix) {
mCanvas.setMatrix(matrix);
}
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.drawColor(0xFFAAAAAA);
super.onDraw(canvas);
mCanvas = canvas;
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
In this method you write, mCanvas = canvas; instead of this write, canvas = mCanvas.
Hello try with below code for paint and capture new bitmap with pain image.first zoom in/out image and on button click draw paint.then click on done button for save your final merge bitmap.Hop its helpful to you.
public class PaintScreen extends Activity {
Context mContext;
private Paint mPaint;
MaskFilter mEmboss;
MaskFilter mBlur;
private LinearLayout mPaintBaseLayout, mPaintBaseLayout2;
private PaintView mPaintView;
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix matrix1 = new Matrix();
Matrix savedMatrix = new Matrix();
Matrix savedMatrix2 = new Matrix();
Matrix dmMtrx = new Matrix();
private int WIDTH = 0;
private int HEIGHT = 1;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int POINT2 = 2;
static final int ZOOM = 3;
int mode = NONE;
private static final float MIN_ZOOM = 0.0f;
private static final float MAX_ZOOM = 1.0f;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
float newDist;
float distanceOffset = 50f;
float minOffset = 50f;
float maxOffset = 10000f;
private boolean falg = true;
private int startval = 0;
Bitmap newbm;
private float finalscale;
Bitmap bm;
private float scaledImageOffsetX;
private float scaledImageOffsetY;
ImageView imageView;
ProgressDialog dialog;
private float[] matrixValues;
Bitmap temp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_main);
this.initialize();
this.PaintSet();
imageView = (ImageView) findViewById(R.id.imageview1);
Button button = (Button) findViewById(R.id.btnzoom);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (falg) {
getFlag(false);
} else {
getFlag(true);
}
}
});
Button btnset = (Button) findViewById(R.id.btnset);
btnset.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startval = 1;
mPaintBaseLayout.setDrawingCacheEnabled(true);
/*newbm = Bitmap.createBitmap(bm.getWidth(),
bm.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newbm);
mPaintBaseLayout.draw(canvas);*/
// mPaintView.clear();
/*
mPaintView.setScaleType(ScaleType.MATRIX);
mPaintView.setMPaint(mPaint);
mPaintView.setImageBitmap(newbm);*/
imageView.setVisibility(View.VISIBLE);
mPaintBaseLayout.setVisibility(View.GONE);
new SaveImageAsynk().execute();
}
});
imageView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix1);
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
start.set(event.getX(), event.getY());
savedMatrix.set(matrix1);
midPoint(mid, event);
// mode = POINT2;
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
distanceOffset = minOffset;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
distanceOffset = minOffset;
break;
case MotionEvent.ACTION_MOVE:
if (mode == POINT2) {
newDist = spacing(event);
if (newDist - oldDist > 5f
|| newDist - oldDist < -5f) {
mode = ZOOM;
} else {
start.set(event.getX(), event.getY());
mode = DRAG;
}
} else if (mode == DRAG) {
matrix1.set(savedMatrix);
matrix1.postTranslate(event.getX() - start.x,
event.getY() - start.y);
} else if (mode == ZOOM) {
newDist = spacing(event);
if (newDist > 10f) {
matrix1.set(savedMatrix);
float scale = newDist / oldDist;
matrix1.postScale(scale, scale, mid.x,
mid.y);
finalscale = scale;
}
}
break;
}
view.setImageMatrix(matrix1);
// matrixTurning(matrix1, view);
return true; // indicate event was handled
}
});
}
class SaveImageAsynk extends AsyncTask<String, String, String>{
Bitmap tempBm;
#Override
protected String doInBackground(String... params) {
temp = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, false);
newbm = Bitmap.createBitmap(mPaintBaseLayout.getWidth(),
mPaintBaseLayout.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newbm);
mPaintBaseLayout.draw(canvas);
tempBm = combineImages(newbm, temp);
if (newbm != null) {
newbm = null;
}
if (temp != null) {
temp = null;
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
imageView.setImageBitmap(tempBm);
try {
dialog.dismiss();
if (dialog != null) {
dialog = null;
}
} catch (Exception e) {
}
}
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(PaintScreen.this);
dialog.setMessage("Loading...");
dialog.show();
}
}
public Bitmap combineImages(Bitmap c, Bitmap s) {
Bitmap cs = null;
int width, height = 0;
if (c.getWidth() > s.getWidth()) {
width = c.getWidth();
height = c.getHeight() + s.getHeight();
} else {
width = s.getWidth();
height = c.getHeight() + s.getHeight();
}
Log.e("hw :", "X = "+width + " Y = "+height);
cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(s,new Matrix(), null);
comboImage.drawBitmap(c,Math.abs(scaledImageOffsetX),Math.abs(scaledImageOffsetY), null);
return cs;
}
private void initialize() {
mPaintBaseLayout = (LinearLayout) findViewById(R.id.paint_paint_base_layout);
mPaintBaseLayout2 = (LinearLayout) findViewById(R.id.paint_paint_base_layout2);
mContext = this;
mPaint = new Paint();
mPaintView = new PaintView(mContext);
mPaintView.setBackgroundColor(Color.TRANSPARENT);
mPaintBaseLayout.addView(mPaintView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mPaintBaseLayout.setBackgroundColor(Color.TRANSPARENT);
// mPaintView.setScaleType(ScaleType.FIT_XY);
mPaintView.setAdjustViewBounds(true);
mPaintView.setMPaint(mPaint);
bm = BitmapFactory.decodeResource(getResources(), R.drawable.nat);
mPaintView.setImageBitmap(bm);
mPaintView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
PaintView view = (PaintView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (falg) {
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
} else {
view.onTouchEvent(event);
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
if (falg) {
oldDist = spacing(event);
if (oldDist > 10f) {
start.set(event.getX(), event.getY());
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
}
break;
case MotionEvent.ACTION_UP:
if (falg) {
mode = NONE;
distanceOffset = minOffset;
}
case MotionEvent.ACTION_POINTER_UP:
if (falg) {
mode = NONE;
distanceOffset = minOffset;
}
break;
case MotionEvent.ACTION_MOVE:
if (falg) {
if (mode == POINT2) {
newDist = spacing(event);
if (newDist - oldDist > 5f
|| newDist - oldDist < -5f) {
mode = ZOOM;
} else {
start.set(event.getX(), event.getY());
mode = DRAG;
}
} else if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
} else if (mode == ZOOM) {
newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
finalscale = scale;
}
}
} else {
view.onTouchEvent(event);
}
break;
}
limitZoom(matrix);
view.setImageMatrix(matrix);
matrixTurning(matrix, view);
RectF r = new RectF();
matrix.mapRect(r);
scaledImageOffsetX = r.left;
scaledImageOffsetY = r.top;
return true;
}
});
}
private void limitZoom(Matrix m) {
float[] values = new float[9];
m.getValues(values);
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
if(scaleX > MAX_ZOOM) {
scaleX = MAX_ZOOM;
} else if(scaleX < MIN_ZOOM) {
scaleX = MIN_ZOOM;
}
if(scaleY > MAX_ZOOM) {
scaleY = MAX_ZOOM;
} else if(scaleY < MIN_ZOOM) {
scaleY = MIN_ZOOM;
}
values[Matrix.MSCALE_X] = scaleX;
values[Matrix.MSCALE_Y] = scaleY;
m.setValues(values);
}
public boolean getFlag(boolean b) {
return falg = b;
}
/** Determine the space between the first two fingers */
private static float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private static 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);
}
private void matrixTurning(Matrix matrix, ImageView view) {
float[] value = new float[9];
matrix.getValues(value);
float[] savedValue = new float[9];
savedMatrix2.getValues(savedValue);
// view size
int width = view.getWidth();
int height = view.getHeight();
// image size
Drawable d = view.getDrawable();
if (d == null)
return;
int imageWidth = d.getIntrinsicWidth();
int imageHeight = d.getIntrinsicHeight();
int scaleWidth = (int) (imageWidth * value[0]);
int scaleHeight = (int) (imageHeight * value[0]);
if (value[2] < width - scaleWidth)
value[2] = width - scaleWidth;
if (value[5] < height - scaleHeight)
value[5] = height - scaleHeight;
if (value[2] > 0)
value[2] = 0;
if (value[5] > 0)
value[5] = 0;
if (value[0] > 10 || value[4] > 10) {
value[0] = savedValue[0];
value[4] = savedValue[4];
value[2] = savedValue[2];
value[5] = savedValue[5];
}
if (imageWidth > width || imageHeight > height) {
if (scaleWidth < width && scaleHeight < height) {
int target = WIDTH;
if (imageWidth < imageHeight)
target = HEIGHT;
if (target == WIDTH)
value[0] = value[4] = (float) width / imageWidth;
if (target == HEIGHT)
value[0] = value[4] = (float) height / imageHeight;
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth == width)
value[0] = value[4] = (float) width / imageWidth;
if (scaleHeight == height)
value[0] = value[4] = (float) height / imageHeight;
}
} else {
if (value[0] < 1)
value[0] = 1;
if (value[4] < 1)
value[4] = 1;
}
scaleWidth = (int) (imageWidth * value[0]);
scaleHeight = (int) (imageHeight * value[4]);
if (scaleWidth < width) {
value[2] = (float) width / 2 - (float) scaleWidth / 2;
}
if (scaleHeight < height) {
value[5] = (float) height / 2 - (float) scaleHeight / 2;
}
matrix.setValues(value);
savedMatrix2.set(matrix);
}
public void PaintSet() {
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(10);
// getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(24, BlurMaskFilter.Blur.NORMAL);
}
public void colorChanged(int color) {
mPaint.setColor(color);
}
}
class PaintView extends ImageView {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
// onDraw
private Paint mPaint;
// onTouch
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
// canvas.drawColor(0xFFAAAAAA);
super.onDraw(canvas);
mCanvas = canvas;
// canvas = mCanvas;
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
// canvas.drawBitmap(mBitmap, PaintScreen.matrix, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
public void clear() {
mPaint.reset();
// invalidate();
}
public void setMPaint(Paint paint) {
mPaint = paint;
}
private void touchStart(float x, float y) {
// 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);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
Log.d("PaintView", "ev ->" + event.getAction());
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;
}
public void cMatrix(Matrix matrix) {
mCanvas.setMatrix(matrix);
}
}

Categories

Resources