Неправильное положение шкалы после применения эффекта масштабирования на холсте Android

Прежде всего, это следующий вопрос, заданный здесь, « Панорама», «Масштаб» и «Масштаб» для пользовательского представления для холста в Android

Поскольку ответа пока нет, я, наконец, решил проблему, используя детекторы жестов-android

После применения жестов масштабирования / масштаба я обнаружил, что координаты рисования холста все еще указывают на старое положение (перед применением увеличения), а не на точные координаты касания. В принципе, я не могу получить правильные координаты холста после масштабирования или перетаскивания холста.

Перед масштабированием,

Введите описание изображения здесь

После масштабирования точки касания рисуют предыдущее местоположение. Я хочу, чтобы он рисовал текущее местоположение касания,

Введите описание изображения здесь

Образец кода,

public class DrawingView extends View { private void setupDrawing() { mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); mgd = new MoveGestureDetector(ctx, mgl); sgd = new ScaleGestureDetector(ctx, sgl); rgd = new RotateGestureDetector(ctx, rgl); } class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); // Don't let the object get too small or too large. mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); invalidate(); return true; } } MoveGestureDetector.SimpleOnMoveGestureListener mgl = new MoveGestureDetector.SimpleOnMoveGestureListener() { @Override public boolean onMove(MoveGestureDetector detector) { PointF delta = detector.getFocusDelta(); matrix.postTranslate(delta.x, delta.y); invalidate(); return true; } }; ScaleGestureDetector.SimpleOnScaleGestureListener sgl = new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScale(ScaleGestureDetector detector) { float scale = detector.getScaleFactor(); matrix.postScale(scale, scale, detector.getFocusX(), detector.getFocusY()); invalidate(); return true; } }; RotateGestureDetector.SimpleOnRotateGestureListener rgl = new RotateGestureDetector.SimpleOnRotateGestureListener() { @Override public boolean onRotate(RotateGestureDetector detector) { matrix.postRotate(-detector.getRotationDegreesDelta(), detector.getFocusX(), detector.getFocusY()); invalidate(); return true; } }; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { //view given size super.onSizeChanged(w, h, oldw, oldh); canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); drawCanvas = new Canvas(canvasBitmap); } private void touch_start(float x, float y) { undonePaths.clear(); drawPath.reset(); drawPath.moveTo(x, y); mX = x; mY = y; } private void touch_move(float x, float y, float x2, float y2) { float dx = Math.abs(x - mX); float dy = Math.abs(y - mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { /* QUad to curves using a quadratic line (basically an ellipse of some sort). LineTo is a straight line. QuadTo will smooth out jaggedies where they turn. */ drawPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); mX = x; mY = y; } } private void touch_up() { drawPath.lineTo(mX, mY); // commit the path to our offscreen drawCanvas.drawPath(drawPath, drawPaint); // kill this so we don't double draw paths.add(drawPath); drawPath = new Path(); drawPath.reset(); invalidate(); } @Override public boolean onTouchEvent(MotionEvent event) { if (isZoomable) { mgd.onTouchEvent(event); sgd.onTouchEvent(event); rgd.onTouchEvent(event); } if (!isTouchable) { return super.onTouchEvent(event); } else { //detect user touch float x = event.getX(); float y = event.getY(); switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: if (!isZoomable) { touch_start(x, y); } invalidate(); break; case MotionEvent.ACTION_MOVE: if (!isZoomable) { //mPositions.add(new Vector2(x - mBitmapBrushDimensions.x / 2, y - mBitmapBrushDimensions.y / 2)); if (isCustomBrush && mBitmapBrushDimensions != null) { mPositions = new Vector2(x - mBitmapBrushDimensions.x / 2, y - mBitmapBrushDimensions.y / 2); touch_move(x, y, x - mBitmapBrushDimensions.x / 2, y - mBitmapBrushDimensions.y / 2); } else { touch_move(x, y, 0, 0); } } invalidate(); break; case MotionEvent.ACTION_UP: if (!isZoomable) { touch_up(); } invalidate(); break; } mScaleDetector.onTouchEvent(event); return true; } } @Override protected void onDraw(Canvas canvas) { canvas.save(); canvas.setMatrix(matrix); for (Path p : paths) { canvas.drawPath(p, drawPaint); drawPaint.setColor(selectedColor); drawPaint.setStrokeWidth(brushSize); canvas.drawPath(drawPath, drawPaint); } canvas.restore(); } } 

PS: MoveGestureDetector () , ScaleGestureDetector () & RotateGestureDetector () – это пользовательские классы, унаследованные от android-gesture-detectors

Solutions Collecting From Web of "Неправильное положение шкалы после применения эффекта масштабирования на холсте Android"

Вот что я сделал. В принципе, вам нужно найти разницу между «старыми» и новыми точками. Перейти к нижней части для важных линий …

 @Override public boolean onScale(ScaleGestureDetector detector) { scaleFactor *= detector.getScaleFactor(); float xDiff = initialFocalPoints[0] - currentFocalPoints[0]; float yDiff = initialFocalPoints[1] - currentFocalPoints[1]; transformMatrix.setScale(scaleFactor, scaleFactor, currentFocalPoints[0], currentFocalPoints[1]); transformMatrix.postTranslate(xDiff, yDiff); child.setImageMatrix(transformMatrix); return true; } @Override public boolean onScaleBegin(ScaleGestureDetector detector){ float startX = detector.getFocusX() + getScrollX(); float startY = detector.getFocusY() + getScrollY(); initialFocalPoints = new float[]{startX, startY}; if(transformMatrix.invert(inverseTransformMatrix)) inverseTransformMatrix.mapPoints(currentFocalPoints, initialFocalPoints); return true; } 

Линии, которые сделали разницу, были следующими:

 float xDiff = initialFocalPoints[0] - currentFocalPoints[0]; float yDiff = initialFocalPoints[1] - currentFocalPoints[1]; transformMatrix.postTranslate(xDiff, yDiff); 

Ответ был таким же простым, как выяснение разницы между двумя точками и перевод изображения каждый раз, когда изображение масштабируется.

Чтобы применить какое-либо преобразование, вы должны понимать правила математики. Он работает как для графики с 2-мя и 3-мя измерениями. То есть, если вы работаете с матрицами преобразования (T), вращения (R), масштабирования (S) для применения любого преобразования, у вас есть масштабный объект сначала (умножьте координаты xyz на эту матрицу S), затем поверните (mult. By R) Затем смените объект на Т. Таким образом, вы применяете поворот в некоторой точке, вам нужно переместить объект на нуль и масштабировать, а затем вернуться к базовой точке. То есть в вашем случае, перед применением шкалы, вы должны сдвинуть (уменьшить) все координаты по касанию, а затем применить масштабную матрицу путем умножения, а затем сдвинуть, увеличив все позиции этим касанием.