Android SDK - 触摸中心不缩放

10
我对我的应用程序有一点问题。我刚刚实现了捏合缩放,但是当我捏合缩放时,图像不会在两个点的中心缩放,就像下面的图像所示。图像1显示我的手指捏合前的位置,而图像2则显示它没有像应该那样在我的手指中心缩小。

图像1与图像2的比较:
image1 image2

这是我的代码:

        package com.jpiionefourone.guitarimage;

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.drawable.Drawable;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.ScaleGestureDetector;
    import android.view.View;

    public class MultiTouchView extends View {
        private Drawable mIcon;
        private float mPosX;
        private float mPosY;

        private float mLastTouchX;
        private float mLastTouchY;

        private static final int INVALID_POINTER_ID = -1;

        // The ‘active pointer’ is the one currently moving our object.
        private int mActivePointerId = INVALID_POINTER_ID;

        private ScaleGestureDetector mScaleDetector;
        private float mScaleFactor = 1.f;


        public MultiTouchView(Context context) {
            this(context, null, 0);
        }

        public MultiTouchView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }

        public MultiTouchView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            mIcon = context.getResources().getDrawable(R.drawable.guitar);
            mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());

            // Create our ScaleGestureDetector
            mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());

        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            // Let the ScaleGestureDetector inspect all events.
            mScaleDetector.onTouchEvent(ev);

            final int action = ev.getAction();
            switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                final float x = ev.getX();
                final float y = ev.getY();

                mLastTouchX = x;
                mLastTouchY = y;
                mActivePointerId = ev.getPointerId(0);
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                final float x = ev.getX(pointerIndex);
                final float y = ev.getY(pointerIndex);

                // Only move if the ScaleGestureDetector isn't processing a gesture.
                if (!mScaleDetector.isInProgress()) {
                    final float dx = x - mLastTouchX;
                    final float dy = y - mLastTouchY;

                    mPosX += dx;
                    mPosY += dy;

                    invalidate();
                }

                mLastTouchX = x;
                mLastTouchY = y;

                break;
            }

            case MotionEvent.ACTION_UP: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_CANCEL: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_POINTER_UP: {
                final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = ev.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }
                break;
            }
            }

            return true;
        }

        @Override
        public void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            canvas.save();
            canvas.translate(mPosX, mPosY);
            canvas.scale(mScaleFactor, mScaleFactor);
            mIcon.draw(canvas);
            canvas.restore();
        }

        private 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;
            }
        }
    }

感谢您的来信,
Jared
2个回答

10

在你的 ScaleListener 类中,你只调整了 mScaleFactor,因此,实际上,你的图像不会围绕多点触摸手势的中心缩放!

另外,你需要更新 mPosXmPosY,以使用不同的缩放中心。

在我自己的一个应用程序中,我使用了类似于以下内容的代码:

final float scale = detector.getScaleFactor();
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor * scale, 5.0f));

if (mScaleFactor < 5f) {
   // 1 Grabbing
   final float centerX = detector.getFocusX();
   final float centerY = detector.getFocusY();
   // 2 Calculating difference
   float diffX = centerX - mPosX;
   float diffY = centerY - mPosY;
   // 3 Scaling difference
   diffX = diffX * scale - diffX;
   diffY = diffY * scale - diffY;
   // 4 Updating image origin
   mPosX -= diffX;
   mPosY -= diffY;
}

基本上,它通过以下步骤计算您的图像原点的相对变化:

  1. 获取您的多点触控手势的原点(getFocus())
  2. 计算图像原点(diffXdiffY)之间的差异
  3. 应用比例因子
  4. 使用缩放后的差异更新图像的原点

这种方法在我的情况下仍然有效。我不知道我们是否都使用了相同的坐标系统,但是这样做可以帮助您正确缩放多点触控手势中心的图像。


1

我花了很长时间才让它工作起来...但是感谢几乎可以工作的代码!我不确定我是在胡闹还是怎么样,但是通过对代码进行这些更改,我成功地使我的缩放工作得像我想要的一样!希望这能为某人节省时间。

mScaleFactor *= detector.getScaleFactor();
mScaleFactor = Math.max(0.5f, Math.min(mScaleFactor, 3.0f));
scale = mScaleFactor / scaleAtm


mTranslateMatrix.preTranslate(diffX, diffY);
mTranslateMatrix.invert(mTranslateMatrixInverse);
mPosX += diffX;
mPosY += diffY;
scaleAtm = mScaleFactor;

初始时,scaleAtm = 1。


不会的。因为你的代码缺失了。scaleAtm是什么?你在哪里使用mTranslateMatrix? - Özgür
嘿,我正在使用略有不同的缩放方式,因为我想在缩放后能够拖动所有内容。你可以在这里找到我正在使用的方法: https://dev59.com/mGcs5IYBdhLWcg3w7II9#12497670 - niksi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接