Android. Controlling zooming speed - android

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.

Related

image scale in android using OpenGL

I'm using opengl to render an image as texture.I want to zoom the texture,so i use ScaleGestureDetector.
Here is my code:
public void scale(float scale, float focusX, float focusY) {
Matrix.setIdentityM(uMVPMatrix, 0);
Matrix.translateM(uMVPMatrix, 0, focusX, focusY, 0f);
Matrix.scaleM(uMVPMatrix, 0, scale, scale, 0);
Matrix.translateM(uMVPMatrix, 0, -focusX, -focusY, 0f);
}
private float scale = 1f;
private float focusX;
private float focusY;
#Override
public boolean onScale(ScaleGestureDetector detector) {
renderer.scale(detector.getScaleFactor() * scale,focusX,focusY);
return false;
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
focusX = (detector.getFocusX() - ScreenDimensionHelper.getScreenWidth(context)/2) / ((float) ScreenDimensionHelper.getScreenWidth(context)/2);
focusY = (ScreenDimensionHelper.getScreenHeight(context)/2- detector.getFocusY()) / ((float) ScreenDimensionHelper.getScreenHeight(context)/2);
return true;
}
#Override
public void onScaleEnd(ScaleGestureDetector detector) {
this.scale = detector.getScaleFactor() * scale;
}
I want to zoom around the position where my finger touch.But I found that while I pinch the image,the image moves as well.Is there some better way to do this?

Scalefactor zoom amount on WebView double tap

I'm implementing a canvas on a WebView and I need to have the canvas scale according to the zoom level of the WebView. Combining canvas.scale() with a SimpleOnScaleListener does the trick. For the double tap, I'm using a GestureDetector which detects when there's a double tap and sets the scale factor accordingly. I'm merely guessing how much it scales when there is a double tap: Setting the scale factor to 2.2f works on a 7in tablet but it scales too much for a 10in.
Is there anyway to programmatically figure out how much the WebView has zoomed in on double tap? I basically need the canvas to synchronize zooming with the WebView.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.scale(mScaleFactor, mScaleFactor, 0, 0);
canvas.drawPath(drawPath, drawPaint);
invalidate();
}
public class ScaleGestureListener extends SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
// Don't let the object get too small or too large.
if(Deal.on == false) {
mScaleFactor *= detector.getScaleFactor();
mScaleFactor = Math.max(1f, Math.min(mScaleFactor, 30.0f));
System.out.println("mScaleFactor: " + mScaleFactor);
}
invalidate();
return true;
}
}
public class DoubleTapListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onDoubleTap(MotionEvent e) {
if (Deal.on == false) {
if (mScaleFactor > 1.0f) {
mScaleFactor = 1.0f;
}else {
mScaleFactor = 2.2f;
}
}
return true;
}
}
You can catch zoom change by extending WebViewClient
public MyWebView(Context context, AttributeSet attrs) {
super(context, attrs);
setWebViewClient(new WebViewClient() {
#Override
public void onScaleChanged(WebView view, float oldScale, float newScale) {
super.onScaleChanged(view, oldScale, newScale);
currentScale = newScale;
}
});
}

Implementing pinch zoom and drag using Android's build in gesture listener and scale listener

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!

Add pinch/zoom gesture for android customview

I am going to draw numerous rectangles on a canvas that will create a map. I want to be able to zoom in and out on different parts of the map. I've looked at the other examples and none have proven successful yet. Any ideas?
public class Int_Map extends View {
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
public Int_Map(Context context) {
super(context);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
public boolean onTouchEvent(MotionEvent event){
mScaleDetector.onTouchEvent(event);
Region region = new Region(0, 0, getWidth(), getHeight()/2);
float x = event.getX();
float y = event.getY();
if(region.contains((int)x, (int)y))
{
Intent intent = new Intent(getContext(), Exhibit1.class);
((Activity)getContext()).startActivity(intent);
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.scale(mScaleFactor, mScaleFactor);
Rect rect = new Rect();
rect.set(0,0, canvas.getWidth(), canvas.getHeight()/2);
Drawable drawable = getResources().getDrawable(R.drawable.exhibit1);
drawable.setBounds(rect);
drawable.draw(canvas);
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
invalidate();
return true;
}
}
}

Image zoom is not proper

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);
}

Categories

Resources