android - Mono Android 双指缩放同时覆盖 ondraw

标签 android zooming pinch

我已经移植了一些 Android 代码,用于将 ImageView 缩放为 Android 的单声道,但我在缩放检测器焦点方面遇到了问题。我需要以编程方式绘制对象,因此我要重写 ondraw 方法。

问题是,当我的缩放比例不是 1 时,如果我捏住绘制对象的一侧,绘制的对象会跳离捏合焦点,最终得到的焦点不是您开始时(如果缩放比例大于 1)。如果缩放比例小于1,则绘制的对象会跳向捏合焦点。

我已经尝试了几乎所有的方法,但我一定是太老太累了,因为我就是想不通。

在ondraw中,我先缩放然后平移,然后在固定点绘制对象。

我是否以正确的方式处理这件事?我在搜索中找不到任何涉及在 Canvas 上的某个点绘制对象同时实现捏缩放的内容。

如果有人能提供帮助,我们将不胜感激。

代码如下...

class clsTarget : ImageView, ImageView.IOnTouchListener
{
    private ScaleGestureDetector mScaleDetector;
    private ScaleListener sListener;
    private static float mScaleFactor = 0.6F;
    private static float scalePointX;
    private static float scalePointY;

    private static int INVALID_POINTER_ID = -1;
    private int mActivePointerId = INVALID_POINTER_ID;
    private static float mPosX, mPosY, mLastTouchX, mLastTouchY;

    public clsTarget(Context context)
        : base(context)
    {
        this.SetOnTouchListener(this);

        sListener = new ScaleListener();
        mScaleDetector = new ScaleGestureDetector(context, sListener);
        mScaleFactor = 800F / (float)Math.Min(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels);
    }

    protected override void OnDraw(Android.Graphics.Canvas canvas)
    {
        canvas.Save();

        canvas.Scale(mScaleFactor, mScaleFactor, scalePointX, scalePointY);
        canvas.Translate(mPosX, mPosY);

        Paint p = new Paint(PaintFlags.AntiAlias);
        p.Color = Color.Orange;
        p.SetStyle(Paint.Style.Fill);
        p.StrokeWidth = 1F;
        canvas.DrawCircle(400, 400, 200, p);

        canvas.Restore();
    }

    public bool OnTouch(View v, MotionEvent e)
    {
        mScaleDetector.OnTouchEvent(e);

        switch (e.Action & MotionEventActions.Mask)
        {
            case MotionEventActions.Down:
                float x = (e.GetX() - scalePointX) / mScaleFactor;
                float y = (e.GetY() - scalePointY) / mScaleFactor;

                mLastTouchX = x;
                mLastTouchY = y;

                mActivePointerId = e.GetPointerId(0);
                break;

            case MotionEventActions.Move:
                int pointerIndex = e.FindPointerIndex(mActivePointerId);

                float x2 = (e.GetX(pointerIndex) - scalePointX) / mScaleFactor;
                float y2 = (e.GetY(pointerIndex) - scalePointY) / mScaleFactor;

                float dx = (x2 - mLastTouchX);
                float dy = (y2 - mLastTouchY);

                if (!mScaleDetector.IsInProgress)
                {
                    mPosX += dx;
                    mPosY += dy;

                    mLastTouchX = x2;
                    mLastTouchY = y2;
                }

                this.Invalidate();

                break;

            case MotionEventActions.Up:
                mActivePointerId = INVALID_POINTER_ID;
                break;

            case MotionEventActions.Cancel:
                mActivePointerId = INVALID_POINTER_ID;
                break;

            case MotionEventActions.PointerUp:
                int pointerIndex2 = (int)(e.Action & MotionEventActions.PointerIndexMask) >> (int)MotionEventActions.PointerIndexShift;
                int pointerID = e.GetPointerId(pointerIndex2);

                if (pointerID == mActivePointerId)
                {
                    int newPointerIndex = pointerIndex2 == 0 ? 1 : 0;

                    mLastTouchX = (e.GetX(newPointerIndex) - scalePointX) / mScaleFactor;
                    mLastTouchY = (e.GetY(newPointerIndex) - scalePointY) / mScaleFactor;

                    mActivePointerId = e.GetPointerId(newPointerIndex);
                }

                break;
        }

        return true;
    }

    private class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener
    {
        public override bool OnScale(ScaleGestureDetector detector)
        {
            scalePointX = detector.FocusX;
            scalePointY = detector.FocusY;

            mScaleFactor *= detector.ScaleFactor;
            mScaleFactor = Math.Max(0.5f, Math.Min(mScaleFactor, 7.0f));

            return true;
        }
    }
}

最佳答案

抱歉,英语不好。

首先,Case MotionEventActions.Move,当ScaleDetector.IsInProgress为true时,设置mLastGestureX和mLastGesturey。

在OnDraw中,当ScaleDetector.IsInProgress为false时, canvas.Scale(mScaleFactor, mScaleFactor,mLastGestureX,mLastGestureY)

代码如下...

class ImageViewExt : ImageView
{
    private static int INVALID_POINTER_ID = -1;
    private float mPosX;
    private float mPosY;
    private float mLastTouchX;
    private float mLastTouchY;
    private float mLastGestureX;
    private float mLastGestureY;
    private int mActivePointerId = INVALID_POINTER_ID;

    private ScaleGestureDetector mScaleDetector;
    private static float mScaleFactor = 1.0f;

    public ImageViewExt(Context context):base(context)
    {
        mScaleDetector = new ScaleGestureDetector(Context,new ScaleListener());
    }

    public override bool OnTouchEvent (MotionEvent e)
    {
        mScaleDetector.OnTouchEvent (e);

        //int action = e.Action;
        switch (e.Action & MotionEventActions.Mask) {
        case MotionEventActions.Down:
            if (!mScaleDetector.IsInProgress) {
                float x = e.GetX ();
                float y = e.GetY ();

                mLastTouchX = x;
                mLastTouchY = y;
                mActivePointerId = e.GetPointerId (0);
            }
            break;
        case MotionEventActions.Pointer1Down:
            if (mScaleDetector.IsInProgress) {
                float gx = mScaleDetector.FocusX;
                float gy = mScaleDetector.FocusY;

                mLastGestureX = gx;
                mLastGestureY = gy;
            }
            break;
        case MotionEventActions.Move:
            if (!mScaleDetector.IsInProgress) {
                int pointerIdx = e.FindPointerIndex (mActivePointerId);
                float x = e.GetX (pointerIdx);
                float y = e.GetY (pointerIdx);

                float dx = x - mLastTouchX;
                float dy = y - mLastTouchY;

                mPosX += dx;
                mPosY += dy;

                Invalidate ();

                mLastTouchX = x;
                mLastTouchY = y;
            } else {
                float gx = mScaleDetector.FocusX;
                float gy = mScaleDetector.FocusY;

                float gdx = gx - mLastGestureX;
                float gdy = gy - mLastGestureY;

                mPosX += gdx;
                mPosY += gdy;

                Invalidate ();

                mLastGestureX = gx;
                mLastGestureY = gy;
            }
            break;
        case MotionEventActions.Up:
            mActivePointerId = INVALID_POINTER_ID;
            break;
        case MotionEventActions.Cancel:
            mActivePointerId = INVALID_POINTER_ID;
            break;
        case MotionEventActions.PointerUp:

            int pointerIdx2 = (int)(e.Action & MotionEventActions.PointerIndexMask) >> (int)MotionEventActions.PointerIndexShift;
            int pointerId = e.GetPointerId (pointerIdx2);

            if (pointerId == mActivePointerId) {
                int NewPointerIndex = pointerIdx2 == 0 ? 1 : 0;
                mLastTouchX = e.GetX (NewPointerIndex);
                mLastTouchY = e.GetY (NewPointerIndex);
                mActivePointerId = e.GetPointerId (NewPointerIndex);
            }
            else{
                int TempPointerIdx = e.FindPointerIndex(mActivePointerId);
                mLastTouchX = e.GetX(TempPointerIdx);
                mLastTouchY = e.GetY(TempPointerIdx);
            }
            break;
        }

        return true;
    }

    protected override void OnDraw (Canvas canvas)
    {
        canvas.Save ();

        canvas.Translate (mPosX, mPosY);
        if (mScaleDetector.IsInProgress) {
            canvas.Scale (mScaleFactor, mScaleFactor, mScaleDetector.FocusX, mScaleDetector.FocusY);
        } else {
            canvas.Scale (mScaleFactor, mScaleFactor,mLastGestureX,mLastGestureY);
        }
        base.OnDraw (canvas);
        canvas.Restore();
    }

    private class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener
    {
        public override bool OnScale (ScaleGestureDetector detector)
        {
            mScaleFactor *= detector.ScaleFactor;

            //小さすぎず大きすぎず処理
            mScaleFactor = Math.Max(0.1f, Math.Min(mScaleFactor, 10.0f));

            return true;
        }

    }
}

关于android - Mono Android 双指缩放同时覆盖 ondraw,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12594918/

相关文章:

css - 在浏览器中放大时的图像替代品

javascript - d3 缩放 : prevent page zoom when using a touchscreen

android - 在 android 2.1 中捏合缩放

Android webview捏缩放问题

android - Admob 横幅广告无法在 Android 上正常运行

Android Volley 意外响应代码 400

android - SwipeRefreshLayout + 另一个 View

android - 显示没有时间的android日期

android - 在应用程序启动时更改缩放级别 Google Maps Api v2

ipad - 在 iPad 模拟器上模拟捏合