You can create a reusable class that implements OnTouchListener
to accomplish this.
public class MyScaleGestures implements OnTouchListener, OnScaleGestureListener {
private View view;
private ScaleGestureDetector gestureScale;
private float scaleFactor = 1;
private boolean inScale = false;
public MyScaleGestures (Context c){ gestureScale = new ScaleGestureDetector(c, this); }
@Override
public boolean onTouch(View view, MotionEvent event) {
this.view = view;
gestureScale.onTouchEvent(event);
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
scaleFactor = (scaleFactor < 1 ? 1 : scaleFactor); // prevent our view from becoming too small //
scaleFactor = ((float)((int)(scaleFactor * 100))) / 100; // Change precision to help with jitter when user just rests their fingers //
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
inScale = true;
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) { inScale = false; }
}
Then assign it as your View
‘s OnTouchListener
like so.
myView.setOnTouchListener(new MyScaleGestures(context));
If you want to add a scrolling ability to the View
you will need to implement onScroll
from the OnGestureListener
interface. You can add this override to the MyScaleGestures
class to accomplish this.
@Override
public boolean onScroll(MotionEvent event1, MotionEvent event2, float x, float y) {
float newX = view.getX();
float newY = view.getY();
if(!inScale){
newX -= x;
newY -= y;
}
WindowManager wm = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
Point p = new Point();
d.getSize(p);
if (newX > (view.getWidth() * scaleFactor - p.x) / 2){
newX = (view.getWidth() * scaleFactor - p.x) / 2;
} else if (newX < -((view.getWidth() * scaleFactor - p.x) / 2)){
newX = -((view.getWidth() * scaleFactor - p.x) / 2);
}
if (newY > (view.getHeight() * scaleFactor - p.y) / 2){
newY = (view.getHeight() * scaleFactor - p.y) / 2;
} else if (newY < -((view.getHeight() * scaleFactor - p.y) / 2)){
newY = -((view.getHeight() * scaleFactor - p.y) / 2);
}
view.setX(newX);
view.setY(newY);
return true;
}
The end result of doing all of the above will give you class like this one:
public class StandardGestures implements OnTouchListener, OnGestureListener, OnDoubleTapListener, OnScaleGestureListener {
private View view;
private GestureDetector gesture;
private ScaleGestureDetector gestureScale;
private float scaleFactor = 1;
private boolean inScale;
public StandardGestures(Context c){
gesture = new GestureDetector(c, this);
gestureScale = new ScaleGestureDetector(c, this);
}
@Override
public boolean onTouch(View view, MotionEvent event) {
this.view = view;
gesture.onTouchEvent(event);
gestureScale.onTouchEvent(event);
return true;
}
@Override
public boolean onDown(MotionEvent event) {
return true;
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2, float x, float y) {
return true;
}
@Override
public void onLongPress(MotionEvent event) {
}
@Override
public boolean onScroll(MotionEvent event1, MotionEvent event2, float x, float y) {
float newX = view.getX();
float newY = view.getY();
if(!inScale){
newX -= x;
newY -= y;
}
WindowManager wm = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
Point p = new Point();
d.getSize(p);
if (newX > (view.getWidth() * scaleFactor - p.x) / 2){
newX = (view.getWidth() * scaleFactor - p.x) / 2;
} else if (newX < -((view.getWidth() * scaleFactor - p.x) / 2)){
newX = -((view.getWidth() * scaleFactor - p.x) / 2);
}
if (newY > (view.getHeight() * scaleFactor - p.y) / 2){
newY = (view.getHeight() * scaleFactor - p.y) / 2;
} else if (newY < -((view.getHeight() * scaleFactor - p.y) / 2)){
newY = -((view.getHeight() * scaleFactor - p.y) / 2);
}
view.setX(newX);
view.setY(newY);
return true;
}
@Override
public void onShowPress(MotionEvent event) {
}
@Override
public boolean onSingleTapUp(MotionEvent event) {
return true;
}
@Override
public boolean onDoubleTap(MotionEvent event) {
view.setVisibility(View.GONE);
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent event) {
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
scaleFactor = scaleFactor < 1 ? 1 : scaleFactor; // prevent our image from becoming too small
scaleFactor = (float) (int) (scaleFactor * 100) / 100; // Change precision to help with jitter when user just rests their fingers //
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
onScroll(null, null, 0, 0); // call scroll to make sure our bounds are still ok //
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
inScale = true;
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
inScale = false;
onScroll(null, null, 0, 0); // call scroll to make sure our bounds are still ok //
}
}