2

Android のイメージビューをモノラルにズームするための Android コードをいくつか移植しましたが、スケール検出器のフォーカス ポイントに問題があります。プログラムでオブジェクトを描画する必要があるため、ondraw メソッドをオーバーライドしています。

問題は、ズーム スケールが 1 以外の場合に、描画オブジェクトの片側をピンチすると、描画オブジェクトがピンチ フォーカス ポイントから離れてしまい、最初とは異なるフォーカス ポイントになってしまうことです。 (ズーム スケールが 1 より大きい場合)。ズーム スケールが 1 未満の場合、描画されたオブジェクトはピンチ フォーカスに向かってジャンプします。

あらゆることを試しましたが、年を取りすぎて疲れているに違いありません。

ondraw では、拡大縮小してから平行移動し、固定点でオブジェクトを描画します。

私はこれを正しい方法で行っていますか?ピンチズームを実装しながら、キャンバス上のポイントにオブジェクトを描画することを含む検索では何も見つかりません。

誰かが助けることができれば、それは大歓迎です。

コードは次のとおりです...

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

1 に答える 1

2

すみません、下手な英語です。

まず、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;
        }

    }
}
于 2012-11-04T11:13:14.077 に答える