简体   繁体   English

Android Canvas - 缩放和翻译

[英]Android Canvas - Scale and Translate

I have an SVG that I want to zoom and pan using gestures in Android. 我有一个SVG,我想在Android中使用手势进行缩放和平移。 It works, but not smoothly enough for my tastes. 它有效,但不够顺畅,不适合我的口味。 So how can I improve this class to have smooth panning that works at all zoom levels and stays under your finger, scales using a pinch gesture zooms from the area of the gesture (AKA focus) and as a bonus double tapping should result in snapping the image back to 1.0? 那么我怎样才能改进这个类以使平滑平移在所有缩放级别下工作并保持在手指下,使用捏合手势缩放来自手势区域(AKA焦点)并且作为奖励双击应该导致捕捉图像回到1.0? I'm using this SVG library . 我正在使用这个SVG库 An acceptable answer should meet these functional requirements, not jump around unexpectedly and stick to GestureDetectors unless a case can be made that they just won't work. 一个可接受的答案应该满足这些功能要求,不要意外跳转并坚持使用GestureDetectors,除非可以说它们不起作用。

public class MapView extends ViewGroup {
    private static final float MINIMUM_SCALE_FACTOR = 1.0f;
    private static final float MAXIMUM_SCALE_FACTOR = 10.0f;

    private Picture mPicture;
    private Paint mPaint;

    private ScaleGestureDetector mScaleDetector;
    private GestureDetector mMoveDetector;

    private float mScaleFactor;
    private float mScaleFocusX;
    private float mScaleFocusY;
    private float mFocusX = 0.0f;
    private float mFocusY = 0.0f;

    private float mImageHeight;
    private float mImageWidth;
    private int mViewHeight;
    private int mViewWidth;
    private RectF mDrawingRect;


    public MapView(Context context) {
        super(context);

        init(context);
    }

    public MapView(Context context, AttributeSet attrs) {
        super(context, attrs);

        init(context);

    }

    public MapView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        init(context);
    }

    public void init(Context context) {
        Log.d(getClass().getCanonicalName(), "Initialized.");

        this.setBackgroundColor(Color.WHITE);

        this.mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.BLUE);
        mPaint.setStrokeWidth(2);
        mPaint.setAntiAlias(true);

        this.mScaleFactor = MINIMUM_SCALE_FACTOR;

        // Setup Gesture Detectors
        this.mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        this.mMoveDetector = new GestureDetector(context, new MoveListener());
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.d(getClass().getCanonicalName(), "onLayout");

        this.mDrawingRect = getDrawingSquare();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        this.mViewWidth = w;
        this.mViewHeight = h;
    }

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

        Log.d(getClass().getCanonicalName(), "onDraw()");

        canvas.save();
        canvas.scale(mScaleFactor, mScaleFactor, mScaleFocusX, mScaleFocusY);

        canvas.translate(mFocusX, mFocusY);

        canvas.drawRect((int) mDrawingRect.left, (int) mDrawingRect.top, (int) mDrawingRect.right, (int) mDrawingRect.bottom, mPaint);
        canvas.drawPicture(mPicture, mDrawingRect);

        canvas.restore();
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        mScaleDetector.onTouchEvent(ev);
        mMoveDetector.onTouchEvent(ev);

        return true;
    }

    public RectF getDrawingSquare() {
        float width = getWidth();
        float height = getHeight();
        Log.d(getClass().getCanonicalName(), "Picture width " + width + " - height " + height);

        float side = Math.min(width, height);

        return new RectF(0, 0, side, side);
    }

    public void setSVG(SVG svg) {
        Log.d(getClass().getCanonicalName(), "SVG to Picture.");

        this.mPicture = svg.getPicture();
        this.mImageHeight = mPicture.getHeight();
        this.mImageWidth = mPicture.getWidth();

        invalidate();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor(); // scale change since previous event
            mScaleFocusX = detector.getFocusX();
            mScaleFocusY = detector.getFocusY();

            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(MINIMUM_SCALE_FACTOR, Math.min(mScaleFactor, MAXIMUM_SCALE_FACTOR));

            invalidate();

            return true;
        }
    }

    private class MoveListener extends GestureDetector.SimpleOnGestureListener {
//        @Override
//        public boolean onDown(MotionEvent e) {
//            return true;
//        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            scrollBy((int)distanceX, (int)distanceY);
//            mFocusX += distanceX;
//            mFocusY += distanceY;
//            return true;
            return true;
        }
    }
}

如果(重新)绘制图片的速度不够快,您可能不得不将其绘制到位图而是滚动它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM