How can I get zoom functionality for images?

后端 未结 13 1178
粉色の甜心
粉色の甜心 2020-11-22 02:13

Is there a common way to show a big image and enable the user to zoom in and out and pan the image?

Until now I found two ways:

  1. overwriting ImageView,
13条回答
  •  北恋
    北恋 (楼主)
    2020-11-22 02:46

    Adding to @Mike's answer. I also needed double tap to restore the image to the original dimensions when first viewed. So I added a whole heap of "orig..." instance variables and added the SimpleOnGestureListener which did the trick.

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Matrix;
    import android.graphics.PointF;
    import android.view.GestureDetector;
    import android.view.MotionEvent;
    import android.view.ScaleGestureDetector;
    import android.view.View;
    import android.widget.ImageView;
    
    public class TouchImageView extends ImageView {
    
        Matrix matrix = new Matrix();
    
        // We can be in one of these 3 states
        static final int NONE = 0;
        static final int DRAG = 1;
        static final int ZOOM = 2;
        int mode = NONE;
    
        // Remember some things for zooming
        PointF last = new PointF();
        PointF start = new PointF();
        float minScale = 1f;
        float maxScale = 3f;
        float[] m;
    
        float redundantXSpace, redundantYSpace, origRedundantXSpace, origRedundantYSpace;;
    
        float width, height;
        static final int CLICK = 3;
        static final float SAVE_SCALE = 1f;
        float saveScale = SAVE_SCALE;
    
        float right, bottom, origWidth, origHeight, bmWidth, bmHeight, origScale, origBottom,origRight;
    
        ScaleGestureDetector mScaleDetector;
        GestureDetector mGestureDetector;
    
        Context context;
    
        public TouchImageView(Context context) {
            super(context);
            super.setClickable(true);
            this.context = context;
            mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    
            matrix.setTranslate(1f, 1f);
            m = new float[9];
            setImageMatrix(matrix);
            setScaleType(ScaleType.MATRIX);
    
            setOnTouchListener(new OnTouchListener() {
    
                @Override
                public boolean onTouch(View v, MotionEvent event) {
    
                    boolean onDoubleTapEvent = mGestureDetector.onTouchEvent(event);
                    if (onDoubleTapEvent) {
                        // Reset Image to original scale values
                        mode = NONE;
                        bottom = origBottom;
                        right = origRight;
                        last = new PointF();
                        start = new PointF();
                        m = new float[9];
                        saveScale = SAVE_SCALE;
                        matrix = new Matrix();
                        matrix.setScale(origScale, origScale);
                        matrix.postTranslate(origRedundantXSpace, origRedundantYSpace);
                        setImageMatrix(matrix);
                        invalidate();
                        return true;
                    } 
    
    
                    mScaleDetector.onTouchEvent(event);
    
                    matrix.getValues(m);
                    float x = m[Matrix.MTRANS_X];
                    float y = m[Matrix.MTRANS_Y];
                    PointF curr = new PointF(event.getX(), event.getY());
    
                    switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        last.set(event.getX(), event.getY());
                        start.set(last);
                        mode = DRAG;
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (mode == DRAG) {
                            float deltaX = curr.x - last.x;
                            float deltaY = curr.y - last.y;
                            float scaleWidth = Math.round(origWidth * saveScale);
                            float scaleHeight = Math.round(origHeight * saveScale);
                            if (scaleWidth < width) {
                                deltaX = 0;
                                if (y + deltaY > 0)
                                    deltaY = -y;
                                else if (y + deltaY < -bottom)
                                    deltaY = -(y + bottom);
                            } else if (scaleHeight < height) {
                                deltaY = 0;
                                if (x + deltaX > 0)
                                    deltaX = -x;
                                else if (x + deltaX < -right)
                                    deltaX = -(x + right);
                            } else {
                                if (x + deltaX > 0)
                                    deltaX = -x;
                                else if (x + deltaX < -right)
                                    deltaX = -(x + right);
    
                                if (y + deltaY > 0)
                                    deltaY = -y;
                                else if (y + deltaY < -bottom)
                                    deltaY = -(y + bottom);
                            }
                            matrix.postTranslate(deltaX, deltaY);
                            last.set(curr.x, curr.y);
                        }
                        break;
    
                    case MotionEvent.ACTION_UP:
                        mode = NONE;
                        int xDiff = (int) Math.abs(curr.x - start.x);
                        int yDiff = (int) Math.abs(curr.y - start.y);
                        if (xDiff < CLICK && yDiff < CLICK)
                            performClick();
                        break;
    
                    case MotionEvent.ACTION_POINTER_UP:
                        mode = NONE;
                        break;
                    }
    
                    setImageMatrix(matrix);
                    invalidate();
    
                    return true; // indicate event was handled
                }
    
            });
    
            mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onDoubleTapEvent(MotionEvent e) {
                    return true;
                }
            });
        }
    
        @Override
        public void setImageBitmap(Bitmap bm) {
            super.setImageBitmap(bm);
            bmWidth = bm.getWidth();
            bmHeight = bm.getHeight();
        }
    
        public void setMaxZoom(float x) {
            maxScale = x;
        }
    
        private class ScaleListener extends
                ScaleGestureDetector.SimpleOnScaleGestureListener {
            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                mode = ZOOM;
                return true;
            }
    
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                float mScaleFactor = (float) Math.min(
                        Math.max(.95f, detector.getScaleFactor()), 1.05);
                float origScale = saveScale;
                saveScale *= mScaleFactor;
                if (saveScale > maxScale) {
                    saveScale = maxScale;
                    mScaleFactor = maxScale / origScale;
                } else if (saveScale < minScale) {
                    saveScale = minScale;
                    mScaleFactor = minScale / origScale;
                }
                right = width * saveScale - width
                        - (2 * redundantXSpace * saveScale);
                bottom = height * saveScale - height
                        - (2 * redundantYSpace * saveScale);
                if (origWidth * saveScale <= width
                        || origHeight * saveScale <= height) {
                    matrix.postScale(mScaleFactor, mScaleFactor, width / 2,
                            height / 2);
                    if (mScaleFactor < 1) {
                        matrix.getValues(m);
                        float x = m[Matrix.MTRANS_X];
                        float y = m[Matrix.MTRANS_Y];
                        if (mScaleFactor < 1) {
                            if (Math.round(origWidth * saveScale) < width) {
                                if (y < -bottom)
                                    matrix.postTranslate(0, -(y + bottom));
                                else if (y > 0)
                                    matrix.postTranslate(0, -y);
                            } else {
                                if (x < -right)
                                    matrix.postTranslate(-(x + right), 0);
                                else if (x > 0)
                                    matrix.postTranslate(-x, 0);
                            }
                        }
                    }
                } else {
                    matrix.postScale(mScaleFactor, mScaleFactor,
                            detector.getFocusX(), detector.getFocusY());
                    matrix.getValues(m);
                    float x = m[Matrix.MTRANS_X];
                    float y = m[Matrix.MTRANS_Y];
                    if (mScaleFactor < 1) {
                        if (x < -right)
                            matrix.postTranslate(-(x + right), 0);
                        else if (x > 0)
                            matrix.postTranslate(-x, 0);
                        if (y < -bottom)
                            matrix.postTranslate(0, -(y + bottom));
                        else if (y > 0)
                            matrix.postTranslate(0, -y);
                    }
                }
                return true;
    
            }
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            width = MeasureSpec.getSize(widthMeasureSpec);
            height = MeasureSpec.getSize(heightMeasureSpec);
            // Fit to screen.
            float scale;
            float scaleX = (float) width / (float) bmWidth;
            float scaleY = (float) height / (float) bmHeight;
            scale = Math.min(scaleX, scaleY);
            matrix.setScale(scale, scale);
            setImageMatrix(matrix);
            saveScale = SAVE_SCALE;
            origScale = scale;
    
            // Center the image
            redundantYSpace = (float) height - (scale * (float) bmHeight);
            redundantXSpace = (float) width - (scale * (float) bmWidth);
            redundantYSpace /= (float) 2;
            redundantXSpace /= (float) 2;
    
            origRedundantXSpace = redundantXSpace;
            origRedundantYSpace = redundantYSpace;
    
            matrix.postTranslate(redundantXSpace, redundantYSpace);
    
            origWidth = width - 2 * redundantXSpace;
            origHeight = height - 2 * redundantYSpace;
            right = width * saveScale - width - (2 * redundantXSpace * saveScale);
            bottom = height * saveScale - height
                    - (2 * redundantYSpace * saveScale);
            origRight = right;
            origBottom = bottom;
            setImageMatrix(matrix);
        }
    
    }
    

提交回复
热议问题