@SuppressLint("ClickableViewAccessibility") @Override public boolean onTouch(View v, MotionEvent event) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } if (mTouchMode == NONE) { mGestureDetector.onTouchEvent(event); } if (!mChart.isDragEnabled() && (!mChart.isScaleXEnabled() && !mChart.isScaleYEnabled())) return true; // Handle touch events here... switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: startAction(event); stopDeceleration(); saveTouchStart(event); break; case MotionEvent.ACTION_POINTER_DOWN: if (event.getPointerCount() >= 2) { mChart.disableScroll(); saveTouchStart(event); // get the distance between the pointers on the x-axis mSavedXDist = getXDist(event); // get the distance between the pointers on the y-axis mSavedYDist = getYDist(event); // get the total distance between the pointers mSavedDist = spacing(event); if (mSavedDist > 10f) { if (mChart.isPinchZoomEnabled()) { mTouchMode = PINCH_ZOOM; } else { if (mSavedXDist > mSavedYDist) mTouchMode = X_ZOOM; else mTouchMode = Y_ZOOM; } } // determine the touch-pointer center midPoint(mTouchPointCenter, event); } break; case MotionEvent.ACTION_MOVE: if (mTouchMode == DRAG) { mChart.disableScroll(); performDrag(event); } else if (mTouchMode == X_ZOOM || mTouchMode == Y_ZOOM || mTouchMode == PINCH_ZOOM) { mChart.disableScroll(); if (mChart.isScaleXEnabled() || mChart.isScaleYEnabled()) performZoom(event); } else if (mTouchMode == NONE && Math.abs( distance(event.getX(), mTouchStartPoint.x, event.getY(), mTouchStartPoint.y)) > 5f) { if (mChart.hasNoDragOffset()) { if (!mChart.isFullyZoomedOut() && mChart.isDragEnabled()) { mTouchMode = DRAG; } else { mLastGesture = ChartGesture.DRAG; if (mChart.isHighlightPerDragEnabled()) performHighlightDrag(event); } } else if (mChart.isDragEnabled()) { mLastGesture = ChartGesture.DRAG; mTouchMode = DRAG; } } break; case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; final int pointerId = event.getPointerId(0); velocityTracker.computeCurrentVelocity(1000, Utils.getMaximumFlingVelocity()); final float velocityY = velocityTracker.getYVelocity(pointerId); final float velocityX = velocityTracker.getXVelocity(pointerId); if (Math.abs(velocityX) > Utils.getMinimumFlingVelocity() || Math.abs(velocityY) > Utils.getMinimumFlingVelocity()) { if (mTouchMode == DRAG && mChart.isDragDecelerationEnabled()) { stopDeceleration(); mDecelerationLastTime = AnimationUtils.currentAnimationTimeMillis(); mDecelerationCurrentPoint = new PointF(event.getX(), event.getY()); mDecelerationVelocity = new PointF(velocityX, velocityY); Utils.postInvalidateOnAnimation( mChart); // This causes computeScroll to fire, recommended for this by Google } } if (mTouchMode == X_ZOOM || mTouchMode == Y_ZOOM || mTouchMode == PINCH_ZOOM || mTouchMode == POST_ZOOM) { mChart.calculateOffsets(); mChart.postInvalidate(); } mTouchMode = NONE; mChart.enableScroll(); if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } endAction(event); break; case MotionEvent.ACTION_POINTER_UP: Utils.velocityTrackerPointerUpCleanUpIfNecessary(event, mVelocityTracker); mTouchMode = POST_ZOOM; break; case MotionEvent.ACTION_CANCEL: mTouchMode = NONE; endAction(event); break; } // Perform the transformation, update the chart // if (needsRefresh()) mMatrix = mChart.getViewPortHandler().refresh(mMatrix, mChart, true); return true; // indicate event was handled }