i have seen many answers about this question. but none of those worked perfectly for me. I just want to know how to display and immageview thumbnail by clicking/touching it into full screen view and also it enables to zoomin zoomout.
thank you
Instead of ImageView Use TouchImageView class and open it in full
Screen
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 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;
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);
}
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();
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();
}
}
Related
I have an ImageView and i want to zoom/drag on by two fingers and draw on it using one finger , but after scaling ImageView , bitmap coordinates and ImageView coordinates doesn't match , to solve this i provided onTouch like this :
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
final int NONE = 0;
final int DRAW = 1;
final int PINCH = 2;
float x,y;
switch (event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
drawStartX = event.getX();
drawStartY = event.getY();
imageMode = DRAW;
break;
case MotionEvent.ACTION_POINTER_DOWN:
//drag
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
x = event.getX(0) - event.getX(1);
y = event.getY(0) - event.getY(1);
oldDistance = (float) Math.sqrt(x * x + y * y);
if (oldDistance > 5f) {
savedMatrix.set(matrix);
x = event.getX(0) + event.getX(1);
y = event.getY(0) + event.getY(1);
mid.set(x / 2, y / 2);
imageMode = PINCH;
}
break;
case MotionEvent.ACTION_UP:
imageMode = NONE;
break;
case MotionEvent.ACTION_POINTER_UP:
imageMode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (imageMode == DRAW) {
float drawEndX = event.getX();
float drawEndY = event.getY();
drawTest(drawStartX/bitmapScale - xTranslate, drawStartY/bitmapScale- yTranslate,drawEndX/bitmapScale - xTranslate,drawEndY/bitmapScale - yTranslate,0);
} else if (imageMode == PINCH) {
x = event.getX(0) - event.getX(1);
y = event.getY(0) - event.getY(1);
float newDistance = (float) Math.sqrt(x * x + y * y);
matrix.set(savedMatrix);
if(newDistance > 5f) {
//drag
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
matrix.postTranslate(dx, dy);
//zoom
float scale = (newDistance / oldDistance);
matrix.postScale(scale, scale);
}
//get matrix
float[] mat = new float[9];
matrix.getValues(mat);
bitmapScale = mat[0];
xTranslate = mat[2];
yTranslate = mat[5];
}
break;
}
view.setImageMatrix(matrix);
return true;
}
drawTest is just a void that draws a line.
pic
in before scale picture i drag my finger on imageview and line drawn in exact position , but after scaling i dragged on same position but result is not right
but it's not working properly. how can i fix it ?
I've tried modifying xml without success.
Currently this happens: The image appears in the center of my TouchImageView.
╔══════════════════════════════════════════════╗
║ TouchImageView ║
║ ╔══════════════╗ ║
║ ║ ║ (Center) ║
║ ║ Actual image ║ ║
║ ║ ║ ║
║ ║ (Center) ║ ║
║ ║ ║ ║
║ ╚══════════════╝ ║
║ ║
╚══════════════════════════════════════════════╝
Want this: The image should appear at the top left corner of my TouchImageView.
╔══════════════════════════════════════════════╗
║╔══════════════╗ ║
║║ ║ ║
║║ Actual image ║ ║
║║ ║ ║
║║ ║ ║
║║ ║ ║
║╚══════════════╝ ║
║ ║
║ TouchImageView ║
╚══════════════════════════════════════════════╝
This is the code for the TouchImageView I'm using.
How do I make the necessary changes so the image appears on the top left corner of the TouchImageView instead of smack in the center?
enter code here
import android.app.Activity;
import android.content.Context;
import android.graphics.Matrix;`enter code here`
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
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 hideSoftKeyboard() {
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(this.getWindowToken(), 0);
}
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);
requestFocus();
hideSoftKeyboard();
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(curr);
start.set(last);
mode = DRAG;
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);
}
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();
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();
}
}
Thanks!
Just remove the translation that centers the image.
// Center the image
float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;
// take out the translation that centers the image
// leave all the other calculations since they are used
// to determine origWidth and origHeight
// matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = viewWidth - 2 * redundantXSpace;
origHeight = viewHeight - 2 * redundantYSpace;
setImageMatrix(matrix);
To support the imageView scaleType (ScaleType.FIT_START and ScaleType.FIT_XY), the following code can be modified in TouchImageView class:
For ScaleType.FIT_START, remove the following line:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// matrix.postTranslate(redundantXSpace, redundantYSpace);
}
For ScaleType.FIT_XY, replace the following line:
#Override
public boolean onScale(ScaleGestureDetector detector) {
// matrix.postScale(scaleFactor, scaleFactor, mViewWidth / 2,
// mViewHeight / 2);
//Replace this line with:
matrix.setScale(scaleX,scaleY);
}
I need to draw the rectangle from the center of the canvas based on ACTION_MOVE.
I tried this way
public class CustomRectangle extends View {
private Bitmap bitTopLeft;
private Bitmap bitTopRight;
private Bitmap bitBottomLeft;
private Bitmap bitBottomRight;
private Paint rectAnglePaint;
private Context context;
private Paint bitmapPaint;
private Rect rect;
private int maxX;
private int maxY;
private int centerX;
private int centerY;
private Paint canvasPaint;
public CustomRectangle(Context context) {
super(context);
this.context = context;
Init();
}
private void Init() {
bitTopLeft = BitmapFactory.decodeResource(context.getResources(),
R.drawable.squarsmall);
bitTopRight = BitmapFactory.decodeResource(context.getResources(),
R.drawable.squarsmall);
bitBottomLeft = BitmapFactory.decodeResource(context.getResources(),
R.drawable.squarsmall);
bitBottomRight = BitmapFactory.decodeResource(context.getResources(),
R.drawable.squarsmall);
rectAnglePaint = new Paint();
rectAnglePaint.setColor(Color.GREEN);
rectAnglePaint.setStrokeWidth(5);
rectAnglePaint.setStyle(Paint.Style.STROKE);
rectAnglePaint = new Paint();
rectAnglePaint.setColor(Color.GREEN);
rectAnglePaint.setStrokeWidth(5);
rectAnglePaint.setStyle(Paint.Style.STROKE);
bitmapPaint = new Paint();
bitmapPaint.setColor(Color.BLACK);
rect = new Rect();
Display display = ((Activity) context).getWindowManager()
.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
maxX = size.x;
maxY = size.y;
centerX = maxX / 2;
centerY = maxY / 2;
rect.left = centerX / 2 + bitBottomRight.getWidth() / 2;
rect.top = centerY / 2 + bitBottomRight.getWidth() / 2;
rect.right = centerX + centerX / 2 + bitBottomRight.getWidth() / 2;
rect.bottom = centerY + centerY / 2 + bitBottomRight.getWidth() / 2;
canvasPaint = new Paint();
canvasPaint.setColor(Color.TRANSPARENT);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPaint(canvasPaint);
// Path p = new Path();
canvas.drawBitmap(bitTopLeft,
rect.left - bitBottomRight.getWidth() / 2, rect.top
- bitBottomRight.getWidth() / 2, bitmapPaint);
canvas.drawBitmap(bitTopRight, rect.right - bitBottomRight.getWidth()
/ 2, rect.top - bitBottomRight.getWidth() / 2, bitmapPaint);
canvas.drawBitmap(bitBottomLeft, rect.left - bitBottomRight.getWidth()
/ 2, rect.bottom - bitBottomRight.getWidth() / 2, bitmapPaint);
canvas.drawBitmap(bitBottomRight,
rect.right - bitBottomRight.getWidth() / 2, rect.bottom
- bitBottomRight.getWidth() / 2, bitmapPaint);
canvas.drawRect(rect, rectAnglePaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
invalidate();
break;
case MotionEvent.ACTION_MOVE:
int currentx = (int) event.getX();
int currenty = (int) event.getY();
Calculatingpoint(currentx, currenty);
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return true;
}
private void Calculatingpoint(int x, int y) {
if (x < maxX && y < maxY) {
int dx = 0;
int dy = 0;
dx = rect.right - x;
dy = rect.bottom - y;
// this is working perfect when i touched right bottom.
rect.inset(dx, dy);
invalidate();
}
}
}
But when i touch other corners the rectangle is gone.
I need to draw the rectangle from center point. i need to increase or decrease the width and height based on the touch.
Please advice, how to achieve this. Please give me samples.
I find the Direction from the user touching position, Here is my updated code.
public class CustomRectangle extends View {
private Bitmap bitTopLeft;
private Bitmap bitTopRight;
private Bitmap bitBottomLeft;
private Bitmap bitBottomRight;
private Paint rectAnglePaint;
private Context context;
private Paint bitmapPaint;
private Rect rect;
private int maxX;
private int maxY;
private int centerX;
private int centerY;
private Paint canvasPaint;
private String direction;
public CustomRectangle(Context context) {
super(context);
this.context = context;
Init();
}
private void Init() {
bitTopLeft = BitmapFactory.decodeResource(context.getResources(),
R.drawable.squarsmall);
bitTopRight = BitmapFactory.decodeResource(context.getResources(),
R.drawable.squarsmall);
bitBottomLeft = BitmapFactory.decodeResource(context.getResources(),
R.drawable.squarsmall);
bitBottomRight = BitmapFactory.decodeResource(context.getResources(),
R.drawable.squarsmall);
rectAnglePaint = new Paint();
rectAnglePaint.setColor(Color.GREEN);
rectAnglePaint.setStrokeWidth(5);
rectAnglePaint.setStyle(Paint.Style.STROKE);
rectAnglePaint = new Paint();
rectAnglePaint.setColor(Color.GREEN);
rectAnglePaint.setStrokeWidth(5);
rectAnglePaint.setStyle(Paint.Style.STROKE);
bitmapPaint = new Paint();
bitmapPaint.setColor(Color.BLACK);
rect = new Rect();
Display display = ((Activity) context).getWindowManager()
.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
maxX = size.x;
maxY = size.y;
centerX = maxX / 2;
centerY = maxY / 2;
rect.left = centerX / 2 + bitBottomRight.getWidth() / 2;
rect.top = centerY / 2 + bitBottomRight.getWidth() / 2;
rect.right = centerX + centerX / 2 + bitBottomRight.getWidth() / 2;
rect.bottom = centerY + centerY / 2 + bitBottomRight.getWidth() / 2;
canvasPaint = new Paint();
canvasPaint.setColor(Color.TRANSPARENT);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPaint(canvasPaint);
// Path p = new Path();
canvas.drawBitmap(bitTopLeft,
rect.left - bitBottomRight.getWidth() / 2, rect.top
- bitBottomRight.getWidth() / 2, bitmapPaint);
canvas.drawBitmap(bitTopRight, rect.right - bitBottomRight.getWidth()
/ 2, rect.top - bitBottomRight.getWidth() / 2, bitmapPaint);
canvas.drawBitmap(bitBottomLeft, rect.left - bitBottomRight.getWidth()
/ 2, rect.bottom - bitBottomRight.getWidth() / 2, bitmapPaint);
canvas.drawBitmap(bitBottomRight,
rect.right - bitBottomRight.getWidth() / 2, rect.bottom
- bitBottomRight.getWidth() / 2, bitmapPaint);
canvas.drawRect(rect, rectAnglePaint);
}
float x1, x2, y1, y2, dx, dy;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x1 = event.getRawX();
y1 = event.getRawY();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
x2 = event.getRawX();
y2 = event.getRawY();
int currentx = (int) event.getX();
int currenty = (int) event.getY();
Calculatingpoint(currentx, currenty);
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return true;
}
private void Calculatingpoint(int x, int y) {
if (x2 < maxX && y2 < maxY) {
int dx = 0;
int dy = 0;
// dx = rect.right - (int)x2 ;
// dy = (int)y2 - rect.top ;
//
// Log.e("dx", ""+dx);
// Log.e("dy", ""+dy);
boolean isLeft = false;
boolean isTop = false;
if (x2 > maxX / 2) {
direction = "right";
isLeft = false;
} else {
direction = "left";
isLeft = true;
}
if (y2 > maxY / 2) {
direction = "bottom";
isTop = false;
} else {
direction = "top";
isTop = true;
}
if (!isLeft && !isTop) {
dx = rect.right - (int) x2;
dy = rect.bottom - (int) y2;
}
if (isLeft && !isTop) {
dx = (int) x2 - rect.left;
dy = rect.bottom - (int) y2;
}
if (isLeft && isTop) {
dx = (int) x2 - rect.left;
dy = (int) y2 - rect.top;
}
if (!isLeft && isTop) {
dx = rect.right - (int) x2;
dy = (int) y2 - rect.top;
}
// this will perfect
rect.inset(dx, dy);
invalidate();
}
}
}
I am developing an interactive video installation with touch screen control via an android device. I came up with the following code for panning, zooming and a pan limit so far. But I can't figure out how to limit the zooming (min/max) and how to avoid that the image get out of the boundaries (it should be displayed on the complete screen without any offset).
Thank you for your help!
public boolean onTouchEvent(MotionEvent me) {
switch (me.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
startPoint.set(me.getX(), me.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(me);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(midPoint, me);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float transX = me.getX() - startPoint.x;
float transY = me.getY() - startPoint.y;
matrix.set(savedMatrix);
float[] f = new float[9];
matrix.getValues(f);
float viewWidth = 1317.0f + 1317.0f * ((f[Matrix.MSCALE_X] - 1) / 1.1365f );
float viewWidth2 = 772.0f + 772.0f * ((f[Matrix.MSCALE_X] - 1) / 1.998f);
float viewHeight = 1097.0f + 1097.0f * ((f[Matrix.MSCALE_X] - 1) / 1.463f);
float viewHeight2 = 749.0f + 749.0f * ((f[Matrix.MSCALE_X] - 1) / 2.994f);
if (f[Matrix.MTRANS_X] + transX < -viewWidth){
Log.e("", "left bound");
transX = -f[Matrix.MTRANS_X] -viewWidth;
}
if(f[Matrix.MTRANS_X] + transX > -viewWidth2 ){
transX = -f[Matrix.MTRANS_X] -viewWidth2;
}
if (f[Matrix.MTRANS_Y] + transY > viewHeight){
transY = -f[Matrix.MTRANS_Y] + viewHeight;
}
if(f[Matrix.MTRANS_Y] + transY < viewHeight2){
transY = -f[Matrix.MTRANS_Y] + viewHeight2;
}
matrix.postTranslate(transX, transY);
} else if (mode == ZOOM) {
float newDist = spacing(me);
if (newDist > 10f) {
Log.e("MainActivity", "Correction: " + Float.toString(newDist / newDist));
float transX = me.getX() - startPoint.x;
float transY = me.getY() - startPoint.y;
matrix.set(savedMatrix);
float scale = newDist / oldDist;
float[] f = new float[9];
matrix.getValues(f);
matrix.postScale(scale, scale, -startPoint.x+300.f, -startPoint.y+900.0f);
if (f[Matrix.MSCALE_X] >= 270.0f) {
matrix.postScale((270.0f)/(f[Matrix.MSCALE_X]/scale), (270.0f)/(f[Matrix.MSCALE_Y]*scale), 0f ,0f);
mode = DRAG;
savedMatrix.set(matrix);
midPoint(midPoint, me);
} else if (f[Matrix.MSCALE_X] < 0.29f) {
matrix.postScale((0.29f)/(f[Matrix.MSCALE_X]/scale), (0.29f)/(f[Matrix.MSCALE_Y]*scale), 0f ,0f);
mode = DRAG;
savedMatrix.set(matrix);
midPoint(midPoint, me);
}
}
}
break;
}
// Matrix
try {
socket = new DatagramSocket();
// socket.setBroadcast(true);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String dataString = matrix.toShortString();
Log.e("Activity_Main", dataString);
try {
DatagramPacket packet = new DatagramPacket(dataString.getBytes(), dataString.length(), serverAddr, PORT);
socket.send(packet);
socket.close();
} catch (Exception e) {
}
return true;
}
#SuppressLint("FloatMath")
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);
}
I'm writing a application that there are a upper-imageview and a scollview under the imageview.
The imageview is used by a class provided by my friend, it supports pinch zoom, but after i zood in the image then i touch the scollview below, the image will resize to fit the imageview's size.
It's a big trouble for me to build my app because i want to scroll the information after zooming.
Then i try to change the scrollview to be a imageview as well, i find that there is not resizimg between two views.
I wonder if it is possible to disable the resizing function for the imageview to implement my idea.
The class below is used for the imageview.
Thank you for solutions.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
public class TouchImageView extends ImageView {
Matrix matrix = new 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;
float redundantXSpace, redundantYSpace;
float width, height;
static final int CLICK = 3;
float saveScale = 1f;
float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
int windowId;
ScaleGestureDetector mScaleDetector;
Context context;
public TouchImageView(Context context,int id) {
super(context);
super.setClickable(true);
this.context = context;
this.windowId=id;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
setBackgroundColor(Color.BLACK);
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
EasyPageActivity.resetView();
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float scaleWidth = Math.round(origWidth * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
if (scaleWidth < width) {
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
} else if (scaleHeight < height) {
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
} else {
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
matrix.postTranslate(deltaX, deltaY);
last.set(curr.x, curr.y);
}
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();
if(windowId==1){
EasyPageActivity.defineId(1);
}
if(windowId==2){
EasyPageActivity.defineId(2);
}
if(windowId==3){
EasyPageActivity.defineId(3);
}
if(windowId==4){
EasyPageActivity.defineId(4);
}
if(windowId==5){
EasyPageActivity.defineId(5);
}
if(windowId==6){
EasyPageActivity.defineId(6);
}
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}
});
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
}
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 = (float)Math.min(Math.max(.301f, detector.getScaleFactor()), 4);
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= width || origHeight * saveScale <= height) {
matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
if (mScaleFactor < 1) {
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (Math.round(origWidth * saveScale) < width) {
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
} else {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
}
}
}
} else {
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
}
return true;
}
}
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
//Fit to screen.
float scale;
float scaleX = (float)width / (float)bmWidth;
float scaleY = (float)height / (float)bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
// Center the image
redundantYSpace = (float)height - (scale * (float)bmHeight) ;
redundantXSpace = (float)width - (scale * (float)bmWidth);
redundantYSpace /= (float)2;
redundantXSpace /= (float)2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = width - 2 * redundantXSpace;
origHeight = height - 2 * redundantYSpace;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
setImageMatrix(matrix);
}
}
Did you find any solution?
If not, then you must understand that your image re-sizes itself to fit the screen in the onMeasure method. So, to detect the problem you must debug and see why onMeasure is called after you change the focus to the ScrollView. Try to put some logs and see the flow of actions.