I want to pinch zoom an image but problem is when I zoom it does not zoom in and out from where my fingers are. It goes to point 0, 0.
Here is my code:
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor = detector.getScaleFactor();
Log.e("ScaleFactor", "" + mScaleFactor);
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.4f, Math.min(mScaleFactor, 5.0f));
if(mScaleFactor>=1)
mScaleFactor=1f;
invalidate();
return true;
}
I tried a lot but could get any way to fix this.
it is useful
private float[] matrixValues = new float[9];
private float maxZoom;
private float minZoom;
private float height;
private float width;
private RectF viewRect;
private void init() {
maxZoom = 4;
minZoom = 0.25f;
height = myimage.getDrawable().getIntrinsicHeight()+20;
width = myimage.getDrawable().getIntrinsicWidth()+20;
viewRect = new RectF(0, 0, myimage.getWidth()+20, myimage.getHeight()+20);
}
Related
I'm creating View that can store, move, zoom and crop a picture. I'm aware about many projects which already done this, so link to other project wouldn't be answer, but i'm not sure that it's possible to achive my request.
So basically i'm using ScaleGestureDetector with ScaleGestureDetector.SimpleOnScaleGestureListener, to scale my Canvas, here's a code:
private float MIN_SCALE_FACTOR = 0.3f;
private float MAX_SCALE_FACTOR = 10.0f;
private float mScaleFactor = 1.f;
private ScaleGestureDetector mScaleDetector;
private ScaleGestureDetector.SimpleOnScaleGestureListener mScaleListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
mScaleFactor = Math.max(MIN_SCALE_FACTOR, Math.min(mScaleFactor, MAX_SCALE_FACTOR));
invalidate();
return super.onScale(detector);
}
};
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap != null) {
canvas.save();
super.onDraw(canvas);
correctPositionValues();
canvas.scale(mScaleFactor, mScaleFactor, mPositionX, mPositionY );
canvas.drawBitmap(mBitmap, mPositionX, mPositionY, null);
canvas.restore();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mScaleDetector.onTouchEvent(event);
}
On my phone scale is happening almoust instantly and this looks bad.
Any suggestions highly appreciated
Scale on the previous scale factor:
private ScaleGestureDetector.SimpleOnScaleGestureListener mScaleListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
private preScaleFactor = 1f;
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor = preScaleFactor*detector.getScaleFactor();
mScaleFactor = Math.max(MIN_SCALE_FACTOR, Math.min(mScaleFactor, MAX_SCALE_FACTOR));
invalidate();
return super.onScale(detector);
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
preScaleFactor = mScaleFactor;
return true;
}
};
Kotlin:
class GestureScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
var multiplierScaleFactor = 0.05f
var scaleFactor = 1f
override fun onScale(detector: ScaleGestureDetector?): Boolean {
val detectorScale = (detector?.scaleFactor ?: 1f)
val realScale = detectorScale - 1f
scaleFactor = (multiplierScaleFactor * realScale) + 1
return super.onScale(detector)
}
}
For the first, need to calculate the difference between detectorScale and 1f (default scale). After that use multiplierScaleFactor (change it for your issue) value for reduce zoom speed/sensivity and return 1f (default scale) to the back.
i have this code for rotation/magnification and move image view,now i need to apply these functions for text view,but i was not successful in this mission,can any one help me to do that whit editing this code or another code?thanks
public class MainActivity extends Activity implements OnTouchListener {
private EditText ed_text;
private ImageView view;
private LinearLayout toolbar_lay;
private FrameLayout frame1;
private Matrix mMatrix = new Matrix();
private float mScaleFactor = .4f;
private float mRotationDegrees = 0.f;
private float mFocusX = 0.f;
private float mFocusY = 0.f;
private int mAlpha = 255;
private int mImageHeight, mImageWidth;
private ImageView background;
private ScaleGestureDetector mScaleDetector;
private RotateGestureDetector mRotateDetector;
private MoveGestureDetector mMoveDetector;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frame3);
background=(ImageView) findViewById(R.id.frame_back);
Display display = getWindowManager().getDefaultDisplay();
mFocusX = display.getWidth()/2f;
mFocusY = display.getHeight()/2f;
// Set this class as touchListener to the ImageView
view = (ImageView) findViewById(R.id.id1);
Intent intent=getIntent();
String path=intent.getStringExtra("mybm");
Bitmap bm=BitmapFactory.decodeFile(path);
view.setImageBitmap(bm);
view.setOnTouchListener(this);
// Determine dimensions of 'earth' image
Drawable d = this.getResources().getDrawable(R.drawable.icon3);
mImageHeight = d.getIntrinsicHeight();
mImageWidth = d.getIntrinsicWidth();
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postTranslate(mFocusX - scaledImageCenterX,
mFocusY - scaledImageCenterY);
view.setImageMatrix(mMatrix);
// Setup Gesture Detectors
mScaleDetector = new ScaleGestureDetector(getApplicationContext(),
new ScaleListener());
mRotateDetector = new RotateGestureDetector(getApplicationContext(),
new RotateListener());
mMoveDetector = new MoveGestureDetector(getApplicationContext(),
new MoveListener());
//mShoveDetector =
new ShoveGestureDetector(getApplicationContext(),
new ShoveListener());
}
#SuppressWarnings("deprecation")
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mRotateDetector.onTouchEvent(event);
mMoveDetector.onTouchEvent(event);
// mShoveDetector.onTouchEvent(event);
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.reset();
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postRotate(mRotationDegrees,
scaledImageCenterX, scaledImageCenterY);
mMatrix.postTranslate(mFocusX - scaledImageCenterX,
mFocusY - scaledImageCenterY);
ImageView view = (ImageView) v;
view.setImageMatrix(mMatrix);
view.setAlpha(mAlpha);
return true; // indicate event was handled
}
private class ScaleListener
extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
return true;
}
}
private class RotateListener
extends RotateGestureDetector.SimpleOnRotateGestureListener
{
#Override
public boolean onRotate(RotateGestureDetector detector) {
mRotationDegrees -= detector.getRotationDegreesDelta();
return true;
}
}
private class MoveListener
extends MoveGestureDetector.SimpleOnMoveGestureListener {
#Override
public boolean onMove(MoveGestureDetector detector) {
PointF d = detector.getFocusDelta();
mFocusX += d.x;
mFocusY += d.y;
// mFocusX = detector.getFocusX();
// mFocusY = detector.getFocusY();
return true;
}
}
}
I think you have right idea going with treating the text as an
ImageView. But drop the conversion from a TextView. Instead treat the text image all along as an ImageView. Create a blank Canvas and a Paint, use Canvas.drawText to draw your text in the appropriate place in the Canvas's bitmap, and then use the image manipulation code above to expand/shrink/rotate your text.
During the past weeks I was looking for appropriate source code showing how to enable zoom and pan functionality on a custom view. All solutions that I found had some problems. For example the movement/zoom was not smooth enough or the view jumped around when releasing one finger after a scaling (two-finger) operation. So I came up with a modified solution that I want to share with you. Suggestions and enhancements are welcomed.
What’s different?
It is bad practice to calculate the difference (distance vector) on any interaction (pan, zoom) between each single events and use it to set new values. If you do so, the action does not look smooth and the view might flicker (jump around in some pixels). A better approach is to remember values when the action starts (onScaleBegin, touch-down) and calculate distances for each event in comparison to those start values.
You could handle finger indices in onTouchEvent to better distinguish between pan/move and zoom/scale interaction.
public class CanvasView extends SurfaceView implements SurfaceHolder.Callback {
final static String TAG = "CanvasView";
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
ScaleGestureDetector mScaleDetector;
InteractionMode mode;
Matrix mMatrix = new Matrix();
float mScaleFactor = 1.f;
float mTouchX;
float mTouchY;
float mTouchBackupX;
float mTouchBackupY;
float mTouchDownX;
float mTouchDownY;
Rect boundingBox = new Rect();
public CanvasView(Context context) {
super(context);
// we need to get a call for onSurfaceCreated
SurfaceHolder sh = this.getHolder();
sh.addCallback(this);
// for zooming (scaling) the view with two fingers
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
boundingBox.set(0, 0, 1024, 768);
paint.setColor(Color.GREEN);
paint.setStyle(Style.STROKE);
setFocusable(true);
// initial center/touch point of the view (otherwise the view would jump
// around on first pan/move touch
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
mTouchX = metrics.widthPixels / 2;
mTouchY = metrics.heightPixels / 2;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mScaleDetector.onTouchEvent(event);
if (!this.mScaleDetector.isInProgress()) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
// similar to ScaleListener.onScaleEnd (as long as we don't
// handle indices of touch events)
mode = InteractionMode.None;
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "Touch down event");
mTouchDownX = event.getX();
mTouchDownY = event.getY();
mTouchBackupX = mTouchX;
mTouchBackupY = mTouchY;
// pan/move started
mode = InteractionMode.Pan;
break;
case MotionEvent.ACTION_MOVE:
// make sure we don't handle the last move event when the first
// finger is still down and the second finger is lifted up
// already after a zoom/scale interaction. see
// ScaleListener.onScaleEnd
if (mode == InteractionMode.Pan) {
Log.d(TAG, "Touch move event");
// get current location
final float x = event.getX();
final float y = event.getY();
// get distance vector from where the finger touched down to
// current location
final float diffX = x - mTouchDownX;
final float diffY = y - mTouchDownY;
mTouchX = mTouchBackupX + diffX;
mTouchY = mTouchBackupY + diffY;
CalculateMatrix(true);
}
break;
}
}
return true;
}
#Override
public void onDraw(Canvas canvas) {
int saveCount = canvas.getSaveCount();
canvas.save();
canvas.concat(mMatrix);
canvas.drawColor(Color.BLACK);
canvas.drawRect(boundingBox, paint);
canvas.restoreToCount(saveCount);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
// otherwise onDraw(Canvas) won't be called
this.setWillNotDraw(false);
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
}
void CalculateMatrix(boolean invalidate) {
float sizeX = this.getWidth() / 2;
float sizeY = this.getHeight() / 2;
mMatrix.reset();
// move the view so that it's center point is located in 0,0
mMatrix.postTranslate(-sizeX, -sizeY);
// scale the view
mMatrix.postScale(mScaleFactor, mScaleFactor);
// re-move the view to it's desired location
mMatrix.postTranslate(mTouchX, mTouchY);
if (invalidate)
invalidate(); // re-draw
}
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
float mFocusStartX;
float mFocusStartY;
float mZoomBackupX;
float mZoomBackupY;
public ScaleListener() {
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = InteractionMode.Zoom;
mFocusStartX = detector.getFocusX();
mFocusStartY = detector.getFocusY();
mZoomBackupX = mTouchX;
mZoomBackupY = mTouchY;
return super.onScaleBegin(detector);
}
#Override
public void onScaleEnd(ScaleGestureDetector detector) {
mode = InteractionMode.None;
super.onScaleEnd(detector);
}
#Override
public boolean onScale(ScaleGestureDetector detector) {
if (mode != InteractionMode.Zoom)
return true;
Log.d(TAG, "Touch scale event");
// get current scale and fix its value
float scale = detector.getScaleFactor();
mScaleFactor *= scale;
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
// get current focal point between both fingers (changes due to
// movement)
float focusX = detector.getFocusX();
float focusY = detector.getFocusY();
// get distance vector from initial event (onScaleBegin) to current
float diffX = focusX - mFocusStartX;
float diffY = focusY - mFocusStartY;
// scale the distance vector accordingly
diffX *= scale;
diffY *= scale;
// set new touch position
mTouchX = mZoomBackupX + diffX;
mTouchY = mZoomBackupY + diffY;
CalculateMatrix(true);
return true;
}
}
}
I am trying to implement pinch zoom and drag using Android's gesture listener and scale listener. The problem is that when I perform pinch zoom, the image (which I am trying to zoom) bounces to a particular location. Also the zoom position is not centered.
The following code demonstrates what I am trying to achieve. Any idea why the image is jumping (and how to correct it) ?
public class CustomView extends View {
Bitmap image;
int screenHeight;
int screenWidth;
Paint paint;
GestureDetector gestures;
ScaleGestureDetector scaleGesture;
float scale = 1.0f;
float horizontalOffset, verticalOffset;
int NORMAL = 0;
int ZOOM = 1;
int DRAG = 2;
boolean isScaling = false;
float touchX, touchY;
int mode = NORMAL;
public CustomView(Context context) {
super(context);
//initializing variables
image = BitmapFactory.decodeResource(getResources(),
R.drawable.image_name);
//This is a full screen view
screenWidth = getResources().getDisplayMetrics().widthPixels;
screenHeight = getResources().getDisplayMetrics().heightPixels;
paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint.setColor(Color.WHITE);
scaleGesture = new ScaleGestureDetector(getContext(),
new ScaleListener());
gestures = new GestureDetector(getContext(), new GestureListener());
mode = NORMAL;
initialize();
}
//Best fit image display on canvas
private void initialize() {
float imgPartRatio = image.getWidth() / (float) image.getHeight();
float screenRatio = (float) screenWidth / (float) screenHeight;
if (screenRatio > imgPartRatio) {
scale = ((float) screenHeight) / (float) (image.getHeight()); // fit height
horizontalOffset = ((float) screenWidth - scale
* (float) (image.getWidth())) / 2.0f;
verticalOffset = 0;
} else {
scale = ((float) screenWidth) / (float) (image.getWidth()); // fit width
horizontalOffset = 0;
verticalOffset = ((float) screenHeight - scale
* (float) (image.getHeight())) / 2.0f;
}
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.drawColor(0, Mode.CLEAR);
canvas.drawColor(Color.WHITE);
if(mode == DRAG || mode == NORMAL) {
//This works perfectly as expected
canvas.translate(horizontalOffset, verticalOffset);
canvas.scale(scale, scale);
canvas.drawBitmap(image, getMatrix(), paint);
}
else if (mode == ZOOM) {
//PROBLEM AREA - when applying pinch zoom,
//the image jumps to a position abruptly
canvas.scale(scale, scale, touchX, touchY);
canvas.drawBitmap(image, getMatrix(), paint);
}
canvas.restore();
}
public class ScaleListener implements OnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactorNew = detector.getScaleFactor();
if (detector.isInProgress()) {
touchX = detector.getFocusX();
touchY = detector.getFocusY();
scale *= scaleFactorNew;
invalidate(0, 0, screenWidth, screenHeight);
}
return true;
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
isScaling = true;
mode=ZOOM;
return true;
}
#Override
public void onScaleEnd(ScaleGestureDetector detector) {
mode = NORMAL;
isScaling = false;
}
}
public class GestureListener implements GestureDetector.OnGestureListener,
GestureDetector.OnDoubleTapListener {
#Override
public boolean onDown(MotionEvent e) {
isScaling = false;
return true;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
if (!isScaling) {
mode = DRAG;
isScaling = false;
horizontalOffset -= distanceX;
verticalOffset -= distanceY;
invalidate(0, 0, screenWidth, screenHeight);
} else {
mode = ZOOM;
isScaling = true;
}
return true;
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
scaleGesture.onTouchEvent(event);
gestures.onTouchEvent(event);
return true;
}
}
Thanks in advance.
I have implemented this behaviour, and I used a matrix to handle all the zooming and scrolling (and rotation, in my case). It makes for neat code and works like clockwork.
Store a Matrix as a class member:
Matrix drawMatrix;
Edit: Store old focus point, used to get the focus shift during scaling.
float lastFocusX;
float lastFocusY;
Edit: Set lastFocus variables in onScaleBegin
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
lastFocusX = detector.getFocusX();
lastFocusY = detector.getFocusY();
return true;
}
Replace your onScale:
#Override
public boolean onScale(ScaleGestureDetector detector) {
Matrix transformationMatrix = new Matrix();
float focusX = detector.getFocusX();
float focusY = detector.getFocusY();
//Zoom focus is where the fingers are centered,
transformationMatrix.postTranslate(-focusX, -focusY);
transformationMatrix.postScale(detector.getScaleFactor(), detector.getScaleFactor());
/* Adding focus shift to allow for scrolling with two pointers down. Remove it to skip this functionality. This could be done in fewer lines, but for clarity I do it this way here */
//Edited after comment by chochim
float focusShiftX = focusX - lastFocusX;
float focusShiftY = focusY - lastFocusY;
transformationMatrix.postTranslate(focusX + focusShiftX, focusY + focusShiftY);
drawMatrix.postConcat(transformationMatrix);
lastFocusX = focusX;
lastFocusY = focusY;
invalidate();
return true;
}
Similarly in onScroll:
#Override
public boolean onScroll(MotionEvent downEvent, MotionEvent currentEvent,
float distanceX, float distanceY) {
drawMatrix.postTranslate(-distanceX, -distanceY);
invalidate();
return true;
}
in onDraw; Draw with your drawMatrix:
canvas.drawBitmap(image, drawMatrix, paint);
Happy coding!
I've got this canvas which the user can add images/text etc to. If the user drags one of the items to either side of the canvas, it should expand if needed. I googled, but couldn't find any reasonable solution. Also, the canvas is about 90% of the screen width, and 70% of the height.. I'm not asking for an entire solution.. I just need a tip on how to do this (Links, docs, whatever)
Well, it's difficult to guess what you're trying to achieve. When you say "it should expand if needed", what do you mean? Expand to fill the parent view? Expand to it's intrinsic size?
Here's some (incomplete) code I use in a custom view class. Most of it is gleaned from multiple solutions on here and I give thanks to the original authors. The onDraw is the most interesting one. When you want to draw (where it says custom drawing here), you don't need to worry about translation or scaling as the canvas itself is translated and scaled. In other words, your x and y co-ords are relative to the view size - simply multiply them by scale.
public class LightsViewer extends ImageView {
private float scale;
// minimum and maximum zoom
private float MIN_ZOOM = 1f;
private float MAX_ZOOM = 5f;
// mid point between fingers to centre scale
private PointF mid = new PointF();
private float scaleFactor = 1.f;
private ScaleGestureDetector detector;
// drag/zoom mode
private final static int NONE = 0;
// current mode
private int mode ;
private float startX = 0f;
private float startY = 0f;
private float translateX = 0f;
private float translateY = 0f;
private float previousTranslateX = 0f;
private float previousTranslateY = 0f;
public LightsViewer(Context context) {
super(context);
detector = new ScaleGestureDetector(getContext(), new ScaleListener());
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
}
public LightsViewer(Context context, AttributeSet attrs) {
super(context,attrs);
detector = new ScaleGestureDetector(getContext(), new ScaleListener());
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int ZOOM = 2;
int DRAG = 1;
if (!allowZooming){return true;}
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
//We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
//amount for each coordinates This works even when we are translating the first time because the initial
//values for these two variables is zero.
startX = event.getX() - previousTranslateX;
startY = event.getY() - previousTranslateY;
break;
case MotionEvent.ACTION_MOVE:
if (mode == ZOOM){
Log.d("LIGHTS","ACTION_MOVE:Move but ZOOM, breaking");
break;}
translateX = event.getX() - startX;
translateY = event.getY() - startY;
//We cannot use startX and startY directly because we have adjusted their values using the previous translation values.
//This is why we need to add those values to startX and startY so that we can get the actual coordinates of the finger.
double distance = Math.sqrt(Math.pow(event.getX() - (startX + previousTranslateX), 2) +
Math.pow(event.getY() - (startY + previousTranslateY), 2)
);
if(distance > 0) {
dragged = true;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
midPoint(mid, event);
mode = ZOOM;
break;
case MotionEvent.ACTION_UP:
mode = NONE;
dragged = false;
//All fingers went up, so let's save the value of translateX and translateY into previousTranslateX and
//previousTranslate
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
//This is not strictly necessary; we save the value of translateX and translateY into previousTranslateX
//and previousTranslateY when the second finger goes up
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
}
detector.onTouchEvent(event);
//We redraw the canvas only in the following cases:
//
// o The mode is ZOOM
// OR
// o The mode is DRAG and the scale factor is not equal to 1 (meaning we have zoomed) and dragged is
// set to true (meaning the finger has actually moved)
if ((mode == DRAG && scaleFactor != 1f && dragged) || mode == ZOOM) {
this.invalidate();
}
return true;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (this.getImageMatrix().isIdentity()){return;}
if (allowZooming){
this.applyMatrix(this.getImageMatrix());
}
}
#Override
public void onDraw(Canvas canvas) {
canvas.save();
// scale the canvas
canvas.scale(scaleFactor, scaleFactor, mid.x, mid.y);
canvas.translate(translateX / scaleFactor, translateY / scaleFactor);
super.onDraw(canvas);
// do custom drawing here...e.g.
canvas.drawCircle(100,100, 3 / scaleFactor,light.paint);
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
return true;
}
}
// calculate the mid point of the first two fingers
private void midPoint(PointF point, MotionEvent event) {
// ...
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
Log.d("LIGHTS", x/2 + "," + y/2);
}
public void setMinZoom(float minZoom){
this.MIN_ZOOM = minZoom;
}
public void applyMatrix(Matrix matrix){
float[] matrixValues = new float[9];
matrix.getValues(matrixValues);
int x = (int)matrixValues[Matrix.MTRANS_X];
int y = (int)matrixValues[Matrix.MTRANS_Y];
float scale = matrixValues[Matrix.MSCALE_X];
if (lights!=null){
for (Light light:lights){
light.setX((int)((light.originalX * scale) + x));
light.setY((int)((light.originalY * scale) + y));
}
}
// if either the x or y translations are less than 0, then the image has been cropped
// so set the min zoom to the ratio of the displayed size and the actual size of the image
if (matrixValues[Matrix.MTRANS_X] < 0 || matrixValues[Matrix.MTRANS_Y] <0){
MIN_ZOOM = displayWidth / this.getDrawable().getIntrinsicWidth();
}else{
MIN_ZOOM = 1;
}
}
public void enableZooming(boolean enable){
allowZooming = enable;
}
public void setScale(float scale){
for (Light light:lights){
light.setX((int)(light.originalX * scale));
light.setY((int)(light.originalY * scale));
}
}
}