@SuppressWarnings("deprecation") @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent event){
  PointF vCenterEnd;
  float vDistEnd;
  if (anim != null && !anim.interruptible) {
    return true;
  }
 else {
    anim=null;
  }
  if (vTranslate == null) {
    return true;
  }
  if (detector == null || detector.onTouchEvent(event)) {
    return true;
  }
  int touchCount=event.getPointerCount();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_1_DOWN:
case MotionEvent.ACTION_POINTER_2_DOWN:
    anim=null;
  maxTouchCount=Math.max(maxTouchCount,touchCount);
if (touchCount >= 2) {
  if (zoomEnabled) {
    float distance=distance(event.getX(0),event.getX(1),event.getY(0),event.getY(1));
    scaleStart=scale;
    vDistStart=distance;
    vTranslateStart=new PointF(vTranslate.x,vTranslate.y);
    vCenterStart=new PointF((event.getX(0) + event.getX(1)) / 2,(event.getY(0) + event.getY(1)) / 2);
  }
 else {
    maxTouchCount=0;
  }
  handler.removeMessages(MESSAGE_LONG_CLICK);
}
 else {
  vTranslateStart=new PointF(vTranslate.x,vTranslate.y);
  vCenterStart=new PointF(event.getX(),event.getY());
  handler.sendEmptyMessageDelayed(MESSAGE_LONG_CLICK,600);
}
return true;
case MotionEvent.ACTION_MOVE:
boolean consumed=false;
if (maxTouchCount > 0) {
if (touchCount >= 2) {
vDistEnd=distance(event.getX(0),event.getX(1),event.getY(0),event.getY(1));
vCenterEnd=new PointF((event.getX(0) + event.getX(1)) / 2,(event.getY(0) + event.getY(1)) / 2);
if (zoomEnabled && (distance(vCenterStart.x,vCenterEnd.x,vCenterStart.y,vCenterEnd.y) > 5 || Math.abs(vDistEnd - vDistStart) > 5 || isPanning)) {
isZooming=true;
isPanning=true;
consumed=true;
scale=Math.min(maxScale,(vDistEnd / vDistStart) * scaleStart);
if (scale <= minScale()) {
  vDistStart=vDistEnd;
  scaleStart=minScale();
  vCenterStart=vCenterEnd;
  vTranslateStart=vTranslate;
}
 else if (panEnabled) {
  float vLeftStart=vCenterStart.x - vTranslateStart.x;
  float vTopStart=vCenterStart.y - vTranslateStart.y;
  float vLeftNow=vLeftStart * (scale / scaleStart);
  float vTopNow=vTopStart * (scale / scaleStart);
  vTranslate.x=vCenterEnd.x - vLeftNow;
  vTranslate.y=vCenterEnd.y - vTopNow;
}
 else if (sRequestedCenter != null) {
  vTranslate.x=(getWidth() / 2) - (scale * sRequestedCenter.x);
  vTranslate.y=(getHeight() / 2) - (scale * sRequestedCenter.y);
}
 else {
  vTranslate.x=(getWidth() / 2) - (scale * (sWidth() / 2));
  vTranslate.y=(getHeight() / 2) - (scale * (sHeight() / 2));
}
fitToBounds(true);
refreshRequiredTiles(false);
}
}
 else if (!isZooming) {
float dx=Math.abs(event.getX() - vCenterStart.x);
float dy=Math.abs(event.getY() - vCenterStart.y);
if (dx > 5 || dy > 5 || isPanning) {
consumed=true;
vTranslate.x=vTranslateStart.x + (event.getX() - vCenterStart.x);
vTranslate.y=vTranslateStart.y + (event.getY() - vCenterStart.y);
float lastX=vTranslate.x;
float lastY=vTranslate.y;
fitToBounds(true);
if (lastX == vTranslate.x || (lastY == vTranslate.y && dy > 10) || isPanning) {
  isPanning=true;
}
 else if (dx > 5) {
  maxTouchCount=0;
  handler.removeMessages(MESSAGE_LONG_CLICK);
}
if (!panEnabled) {
  vTranslate.x=vTranslateStart.x;
  vTranslate.y=vTranslateStart.y;
}
refreshRequiredTiles(false);
}
}
}
if (consumed) {
handler.removeMessages(MESSAGE_LONG_CLICK);
invalidate();
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_2_UP:
handler.removeMessages(MESSAGE_LONG_CLICK);
if (maxTouchCount > 0 && (isZooming || isPanning)) {
if (isZooming && touchCount == 2) {
isPanning=true;
vTranslateStart=new PointF(vTranslate.x,vTranslate.y);
if (event.getActionIndex() == 1) {
vCenterStart=new PointF(event.getX(0),event.getY(0));
}
 else {
vCenterStart=new PointF(event.getX(1),event.getY(1));
}
}
if (touchCount < 3) {
isZooming=false;
}
if (touchCount < 2) {
isPanning=false;
maxTouchCount=0;
}
refreshRequiredTiles(true);
return true;
}
if (touchCount == 1) {
isZooming=false;
isPanning=false;
maxTouchCount=0;
}
return true;
}
return super.onTouchEvent(event);
}

@ SuppressWarnings ( "deprecation" ) @ SuppressLint ( "ClickableViewAccessibility" ) @ Override public boolean onTouchEvent ( MotionEvent event ) { PointF vCenterEnd ; float vDistEnd ; if ( anim != null && ! anim . interruptible ) { return true ; } else { anim = null ; } if ( vTranslate == null ) { return true ; } if ( detector == null || detector . onTouchEvent ( event ) ) { return true ; } int touchCount = event . getPointerCount ( ) ; switch ( event . getAction ( ) ) { case MotionEvent . ACTION_DOWN : case MotionEvent . ACTION_POINTER_1_DOWN : case MotionEvent . ACTION_POINTER_2_DOWN : anim = null ; maxTouchCount = Math . max ( maxTouchCount , touchCount ) ; if ( touchCount >= 2 ) { if ( zoomEnabled ) { float distance = distance ( event . getX ( 0 ) , event . getX ( 1 ) , event . getY ( 0 ) , event . getY ( 1 ) ) ; scaleStart = scale ; vDistStart = distance ; vTranslateStart = new PointF ( vTranslate . x , vTranslate . y ) ; vCenterStart = new PointF ( ( event . getX ( 0 ) + event . getX ( 1 ) ) / 2 , ( event . getY ( 0 ) + event . getY ( 1 ) ) / 2 ) ; } else { maxTouchCount = 0 ; } handler . removeMessages ( MESSAGE_LONG_CLICK ) ; } else { vTranslateStart = new PointF ( vTranslate . x , vTranslate . y ) ; vCenterStart = new PointF ( event . getX ( ) , event . getY ( ) ) ; handler . sendEmptyMessageDelayed ( MESSAGE_LONG_CLICK , 600 ) ; } return true ; case MotionEvent . ACTION_MOVE : boolean consumed = false ; if ( maxTouchCount > 0 ) { if ( touchCount >= 2 ) { vDistEnd = distance ( event . getX ( 0 ) , event . getX ( 1 ) , event . getY ( 0 ) , event . getY ( 1 ) ) ; vCenterEnd = new PointF ( ( event . getX ( 0 ) + event . getX ( 1 ) ) / 2 , ( event . getY ( 0 ) + event . getY ( 1 ) ) / 2 ) ; if ( zoomEnabled && ( distance ( vCenterStart . x , vCenterEnd . x , vCenterStart . y , vCenterEnd . y ) > 5 || Math . abs ( vDistEnd - vDistStart ) > 5 || isPanning ) ) { isZooming = true ; isPanning = true ; consumed = true ; scale = Math . min ( maxScale , ( vDistEnd / vDistStart ) * scaleStart ) ; if ( scale <= minScale ( ) ) { vDistStart = vDistEnd ; scaleStart = minScale ( ) ; vCenterStart = vCenterEnd ; vTranslateStart = vTranslate ; } else if ( panEnabled ) { float vLeftStart = vCenterStart . x - vTranslateStart . x ; float vTopStart = vCenterStart . y - vTranslateStart . y ; float vLeftNow = vLeftStart * ( scale / scaleStart ) ; float vTopNow = vTopStart * ( scale / scaleStart ) ; vTranslate . x = vCenterEnd . x - vLeftNow ; vTranslate . y = vCenterEnd . y - vTopNow ; } else if ( sRequestedCenter != null ) { vTranslate . x = ( getWidth ( ) / 2 ) - ( scale * sRequestedCenter . x ) ; vTranslate . y = ( getHeight ( ) / 2 ) - ( scale * sRequestedCenter . y ) ; } else { vTranslate . x = ( getWidth ( ) / 2 ) - ( scale * ( sWidth ( ) / 2 ) ) ; vTranslate . y = ( getHeight ( ) / 2 ) - ( scale * ( sHeight ( ) / 2 ) ) ; } fitToBounds ( true ) ; refreshRequiredTiles ( false ) ; } } else if ( ! isZooming ) { float dx = Math . abs ( event . getX ( ) - vCenterStart . x ) ; float dy = Math . abs ( event . getY ( ) - vCenterStart . y ) ; if ( dx > 5 || dy > 5 || isPanning ) { consumed = true ; vTranslate . x = vTranslateStart . x + ( event . getX ( ) - vCenterStart . x ) ; vTranslate . y = vTranslateStart . y + ( event . getY ( ) - vCenterStart . y ) ; float lastX = vTranslate . x ; float lastY = vTranslate . y ; fitToBounds ( true ) ; if ( lastX == vTranslate . x || ( lastY == vTranslate . y && dy > 10 ) || isPanning ) { isPanning = true ; } else if ( dx > 5 ) { maxTouchCount = 0 ; handler . removeMessages ( MESSAGE_LONG_CLICK ) ; } if ( ! panEnabled ) { vTranslate . x = vTranslateStart . x ; vTranslate . y = vTranslateStart . y ; } refreshRequiredTiles ( false ) ; } } } if ( consumed ) { handler . removeMessages ( MESSAGE_LONG_CLICK ) ; invalidate ( ) ; return true ; } break ; case MotionEvent . ACTION_UP : case MotionEvent . ACTION_POINTER_UP : case MotionEvent . ACTION_POINTER_2_UP : handler . removeMessages ( MESSAGE_LONG_CLICK ) ; if ( maxTouchCount > 0 && ( isZooming || isPanning ) ) { if ( isZooming && touchCount == 2 ) { isPanning = true ; vTranslateStart = new PointF ( vTranslate . x , vTranslate . y ) ; if ( event . getActionIndex ( ) == 1 ) { vCenterStart = new PointF ( event . getX ( 0 ) , event . getY ( 0 ) ) ; } else { vCenterStart = new PointF ( event . getX ( 1 ) , event . getY ( 1 ) ) ; } } if ( touchCount < 3 ) { isZooming = false ; } if ( touchCount < 2 ) { isPanning = false ; maxTouchCount = 0 ; } refreshRequiredTiles ( true ) ; return true ; } if ( touchCount == 1 ) { isZooming = false ; isPanning = false ; maxTouchCount = 0 ; } return true ; } return super . onTouchEvent ( event ) ; }
handle touch events . one finger pans , and two finger pinch and zoom plus panning .
