private void fling(float vx, float vy) { // 以修正动画为大,遇到修正动画正在执行,就不执行惯性动画 if (!(mScaleAnimator != null && mScaleAnimator.isRunning()) && getDrawable() != null) { if (mFlingAnimator != null) { mFlingAnimator.cancel(); mFlingAnimator = null; } mFlingAnimator = new FlingAnimator(new float[] {vx / 1000 * 16, vy / 1000 * 16}); mFlingAnimator.start(); } }
public boolean animFromTo(Matrix matrixFrom, Matrix matrixTo) { if (getDrawable() == null) { return false; } if (mScaleAnimator != null) { mScaleAnimator.cancel(); mScaleAnimator = null; } if (mFlingAnimator != null) { mFlingAnimator.cancel(); mFlingAnimator = null; } mScaleAnimator = new ScaleAnimator(matrixFrom, matrixTo); mScaleAnimator.start(); return true; }
// 停止所有动画,重置位置到fit center状态 public void reset() { mOuterMatrix = new Matrix(); onOuterMatrixChanged(); mPinchMode = PINCH_MODE_FREE; mLastMovePoint = new PointF(); mScaleCenter = new PointF(); mScaleBase = 0; if (mScaleAnimator != null) { mScaleAnimator.cancel(); mScaleAnimator = null; } if (mFlingAnimator != null) { mFlingAnimator.cancel(); mFlingAnimator = null; } invalidate(); }
// 当缩放操作结束如果不在正确位置用动画恢复 private void scaleEnd() { // 不允许动画过程中再触发 if ((mScaleAnimator != null && mScaleAnimator.isRunning()) || getDrawable() == null) { return; } // 是否修正了位置 boolean change = false; // 获取图片整体的变换矩阵 Matrix currentMatrix = getCurrentImageMatrix(); // 整体缩放比例 float currentScale = MathUtils.getMatrixScale(currentMatrix)[0]; // 第二层缩放比例 float outerScale = MathUtils.getMatrixScale(mOuterMatrix)[0]; // 控件大小 float displayWidth = getMeasuredWidth(); float displayHeight = getMeasuredHeight(); float maxScale = getMaxScale(); // 比例修正 float scalePost = 1; // 位置修正 float postX = 0; float postY = 0; // 如果整体缩放比例大于最大比例,进行缩放修正 if (currentScale > maxScale) { scalePost = maxScale / currentScale; } // 如果缩放修正后整体导致第二层缩放小于1(就是图片比fit center状态还小),重新修正缩放 if (outerScale * scalePost < 1) { scalePost = 1 / outerScale; } // 如果修正不为1,说明进行了修正 if (scalePost != 1) { change = true; } // 尝试根据缩放点进行缩放修正 Matrix testMatrix = new Matrix(currentMatrix); testMatrix.postScale(scalePost, scalePost, mLastMovePoint.x, mLastMovePoint.y); RectF testBound = new RectF(0, 0, getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight()); // 获取缩放修正后的图片方框 testMatrix.mapRect(testBound); // 检测缩放修正后位置有无超出,如果超出进行位置修正 if (testBound.right - testBound.left < displayWidth) { postX = displayWidth / 2 - (testBound.right + testBound.left) / 2; } else if (testBound.left > 0) { postX = -testBound.left; } else if (testBound.right < displayWidth) { postX = displayWidth - testBound.right; } if (testBound.bottom - testBound.top < displayHeight) { postY = displayHeight / 2 - (testBound.bottom + testBound.top) / 2; } else if (testBound.top > 0) { postY = -testBound.top; } else if (testBound.bottom < displayHeight) { postY = displayHeight - testBound.bottom; } // 如果位置修正不为0,说明进行了修正 if (postX != 0 || postY != 0) { change = true; } // 只有有执行修正才执行动画 if (change) { // 如果up的时候触发惯性,这里需要取消掉,以修正动画为主 if (mFlingAnimator != null) { mFlingAnimator.cancel(); mFlingAnimator = null; } // 动画开始举证 Matrix animStart = new Matrix(mOuterMatrix); // 计算结束举证 Matrix animEnd = new Matrix(mOuterMatrix); animEnd.postScale(scalePost, scalePost, mLastMovePoint.x, mLastMovePoint.y); animEnd.postTranslate(postX, postY); // 启动矩阵动画 mScaleAnimator = new ScaleAnimator(animStart, animEnd); mScaleAnimator.start(); } }
// 双击后放大或者缩小 // 当当前缩放比例大于等于1,那么双击放大到MaxScale // 当当前缩放比例小于1,双击放大到1 // 当当前缩放比例等于MaxScale,双击缩小到屏幕大小 private void doubleTap(float x, float y) { // 不允许动画过程中再触发 if ((mScaleAnimator != null && mScaleAnimator.isRunning()) || getDrawable() == null) { return; } // 获取第一层变换矩阵 Matrix innerMatrix = getInnerMatrix(); // 当前总的缩放比例 float innerScale = MathUtils.getMatrixScale(innerMatrix)[0]; float outerScale = MathUtils.getMatrixScale(mOuterMatrix)[0]; float currentScale = innerScale * outerScale; // 控件大小 float displayWidth = getMeasuredWidth(); float displayHeight = getMeasuredHeight(); // 最大放大大小 float maxScale = getMaxScale(); // 接下来要放大的大小 float nextScale = calculateNextScale(innerScale, outerScale); // 如果接下来放大大于最大值或者小于fit center值,则取边界 if (nextScale < innerScale) { nextScale = innerScale; } else if (nextScale > maxScale) { nextScale = maxScale; } // 缩放动画初始矩阵为当前矩阵值 Matrix animStart = new Matrix(mOuterMatrix); // 开始计算缩放动画的结果矩阵 Matrix animEnd = new Matrix(mOuterMatrix); // 计算还需缩放的倍数 animEnd.postScale(nextScale / currentScale, nextScale / currentScale, x, y); // 将放大点移动到控件中心 animEnd.postTranslate(displayWidth / 2 - x, displayHeight / 2 - y); // 得到放大之后的图片方框 Matrix testMatrix = new Matrix(innerMatrix); testMatrix.postConcat(animEnd); RectF testBound = new RectF(0, 0, getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight()); testMatrix.mapRect(testBound); // 修正位置 float postX = 0; float postY = 0; if (testBound.right - testBound.left < displayWidth) { postX = displayWidth / 2 - (testBound.right + testBound.left) / 2; } else if (testBound.left > 0) { postX = -testBound.left; } else if (testBound.right < displayWidth) { postX = displayWidth - testBound.right; } if (testBound.bottom - testBound.top < displayHeight) { postY = displayHeight / 2 - (testBound.bottom + testBound.top) / 2; } else if (testBound.top > 0) { postY = -testBound.top; } else if (testBound.bottom < displayHeight) { postY = displayHeight - testBound.bottom; } // 应用修正位置 animEnd.postTranslate(postX, postY); // 如果正在执行惯性动画,则取消掉 if (mFlingAnimator != null) { mFlingAnimator.cancel(); mFlingAnimator = null; } // 启动矩阵动画 mScaleAnimator = new ScaleAnimator(animStart, animEnd); mScaleAnimator.start(); }
@Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); if (mPinchMode == PINCH_MODE_NO_PINCH) { return true; } // 无论如何都处理各种外部手势 mGestureDetector.onTouchEvent(event); int action = event.getAction() & MotionEvent.ACTION_MASK; // 最后一个点抬起或者取消,结束所有模式 if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (mPinchMode == PINCH_MODE_SCALE) { scaleEnd(); } mPinchMode = PINCH_MODE_FREE; } else if (action == MotionEvent.ACTION_POINTER_UP) { if (mPinchMode == PINCH_MODE_SCALE) { // 抬起的点如果大于2,那么缩放模式还有效,但是有可能初始点变了,重新测量初始点 if (event.getPointerCount() > 2) { // 如果还没结束缩放模式,但是第一个点抬起了,那么让第二个点和第三个点作为缩放控制点 if (event.getAction() >> 8 == 0) { saveScaleContext(event.getX(1), event.getY(1), event.getX(2), event.getY(2)); // 如果还没结束缩放模式,但是第二个点抬起了,那么让第一个点和第三个点作为缩放控制点 } else if (event.getAction() >> 8 == 1) { saveScaleContext(event.getX(0), event.getY(0), event.getX(2), event.getY(2)); } } } // 第一个点按下,开启滚动模式,记录开始滚动的点 } else if (action == MotionEvent.ACTION_DOWN) { // 在矩阵动画过程中不允许启动滚动模式 if (!(mScaleAnimator != null && mScaleAnimator.isRunning())) { // 停止惯性滚动 if (mFlingAnimator != null) { mFlingAnimator.cancel(); mFlingAnimator = null; } mPinchMode = PINCH_MODE_SCROLL; mLastMovePoint.set(event.getX(), event.getY()); } // 非第一个点按下,关闭滚动模式,开启缩放模式,记录缩放模式的一些初始数据 } else if (action == MotionEvent.ACTION_POINTER_DOWN) { // 停止惯性滚动 if (mFlingAnimator != null) { mFlingAnimator.cancel(); mFlingAnimator = null; } // 停止矩阵动画 if (mScaleAnimator != null) { mScaleAnimator.cancel(); mScaleAnimator = null; } mPinchMode = PINCH_MODE_SCALE; saveScaleContext(event.getX(0), event.getY(0), event.getX(1), event.getY(1)); } else if (action == MotionEvent.ACTION_MOVE) { if (!(mScaleAnimator != null && mScaleAnimator.isRunning())) { // 在滚动模式下移动 if (mPinchMode == PINCH_MODE_SCROLL) { // 每次移动产生一个差值累积到图片位置上 scrollBy(event.getX() - mLastMovePoint.x, event.getY() - mLastMovePoint.y); // 记录新的移动点 mLastMovePoint.set(event.getX(), event.getY()); // 在缩放模式下移动 } else if (mPinchMode == PINCH_MODE_SCALE && event.getPointerCount() > 1) { // 两个缩放点间的距离 float distance = MathUtils.getDistance(event.getX(0), event.getY(0), event.getX(1), event.getY(1)); // 保存缩放点中点 float[] lineCenter = MathUtils.getCenterPoint(event.getX(0), event.getY(0), event.getX(1), event.getY(1)); mLastMovePoint.set(lineCenter[0], lineCenter[1]); // 处理缩放 scale(mScaleCenter, mScaleBase, distance, mLastMovePoint); } } } return true; }