question: @ 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 ) ; }
target:  Handle touch events. One finger pans, and two finger pinch and zoom plus panning.