public void computeScroll() { if (mDecelerationVelocity.x == 0.f && mDecelerationVelocity.y == 0.f) return; // There's no deceleration in progress final long currentTime = AnimationUtils.currentAnimationTimeMillis(); mDecelerationVelocity.x *= mChart.getDragDecelerationFrictionCoef(); mDecelerationVelocity.y *= mChart.getDragDecelerationFrictionCoef(); final float timeInterval = (float) (currentTime - mDecelerationLastTime) / 1000.f; float distanceX = mDecelerationVelocity.x * timeInterval; float distanceY = mDecelerationVelocity.y * timeInterval; mDecelerationCurrentPoint.x += distanceX; mDecelerationCurrentPoint.y += distanceY; MotionEvent event = MotionEvent.obtain( currentTime, currentTime, MotionEvent.ACTION_MOVE, mDecelerationCurrentPoint.x, mDecelerationCurrentPoint.y, 0); performDrag(event); event.recycle(); mMatrix = mChart.getViewPortHandler().refresh(mMatrix, mChart, false); mDecelerationLastTime = currentTime; if (Math.abs(mDecelerationVelocity.x) >= 0.01 || Math.abs(mDecelerationVelocity.y) >= 0.01) Utils.postInvalidateOnAnimation( mChart); // This causes computeScroll to fire, recommended for this by Google else { // Range might have changed, which means that Y-axis labels // could have changed in size, affecting Y-axis size. // So we need to recalculate offsets. mChart.calculateOffsets(); mChart.postInvalidate(); stopDeceleration(); } }
@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: 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 { if (mChart.isHighlightPerDragEnabled()) performHighlightDrag(event); } } else if (mChart.isDragEnabled()) { 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) { // Range might have changed, which means that Y-axis labels // could have changed in size, affecting Y-axis size. // So we need to recalculate offsets. mChart.calculateOffsets(); mChart.postInvalidate(); } mTouchMode = NONE; mChart.enableScroll(); if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } break; case MotionEvent.ACTION_POINTER_UP: Utils.velocityTrackerPointerUpCleanUpIfNecessary(event, mVelocityTracker); mTouchMode = POST_ZOOM; break; case MotionEvent.ACTION_CANCEL: mTouchMode = NONE; break; } // Perform the transformation, update the chart // if (needsRefresh()) mMatrix = mChart.getViewPortHandler().refresh(mMatrix, mChart, true); return true; // indicate event was handled }