Android ImageView Zoom-in and Zoom-Out

前端 未结 23 2159
死守一世寂寞
死守一世寂寞 2020-11-22 09:31

I want to Zoom-in and Zoom-out an Android ImageView. I tried most of the samples but in all of them the image in the ImageView itself is getting Zoomed-in and Zoomed-out, wh

23条回答
  •  自闭症患者
    2020-11-22 10:19

    I think Chirag Ravals' answer is great!

    The only thing it could be improved is moving all this code inside some class like:

    PinchZoomImageView extends ImageView {...
    

    and adding there initial Image Matrix initialization to prevent zooming after the first tap:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        matrix = new Matrix(this.getImageMatrix());
    }
    

    BTW, this will fix a bug mentioned by Muhammad Umar and Baz

    P.S. Having Max and Min zoom limits could be also useful. E.g Max zoom is 2X and min zoom is the original scale when the image is fitted to screen:

    static final int MAX_SCALE_FACTOR = 2;
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
        // Getting initial Image matrix
        mViewMatrix = new Matrix(this.getImageMatrix());
        mMinScaleMatrix = new Matrix(mViewMatrix);
        float initialScale = getMatrixScale(mViewMatrix);
    
    
        if (initialScale < 1.0f) // Image is bigger than screen
            mMaxScale = MAX_SCALE_FACTOR;
        else
            mMaxScale = MAX_SCALE_FACTOR * initialScale;
    
        mMinScale = getMatrixScale(mMinScaleMatrix);
    }
    
    
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        ImageView view = (ImageView) v;
        // We set scale only after onMeasure was called and automatically fit image to screen
        if(!mWasScaleTypeSet) {
            view.setScaleType(ImageView.ScaleType.MATRIX);
            mWasScaleTypeSet = true;
        }
    
        float scale;
    
        dumpEvent(event);
    
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: // first finger down only
            mCurSavedMatrix.set(mViewMatrix);
            start.set(event.getX(), event.getY());
            mCurrentMode = DRAG;
            break;
    
        case MotionEvent.ACTION_UP: // first finger lifted
        case MotionEvent.ACTION_POINTER_UP: // second finger lifted
            mCurrentMode = NONE;
    
            float resScale = getMatrixScale(mViewMatrix);
    
            if (resScale > mMaxScale) {
                downscaleMatrix(resScale, mViewMatrix);
            } else if (resScale < mMinScale)
                mViewMatrix = new Matrix(mMinScaleMatrix);
            else if ((resScale - mMinScale) < 0.1f) // Don't allow user to drag picture outside in case of FIT TO WINDOW zoom
                mViewMatrix = new Matrix(mMinScaleMatrix);
            else
                break;
    
            break;
    
        case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
            mOldDist = spacing(event);
            Helper.LOGD(TAG, "oldDist=" + mOldDist);
            if (mOldDist > 5f) {
                mCurSavedMatrix.set(mViewMatrix);
                midPoint(mCurMidPoint, event);
                mCurrentMode = ZOOM;
                Helper.LOGD(TAG, "mode=ZOOM");
            }
            break;
    
        case MotionEvent.ACTION_MOVE:
            if (mCurrentMode == DRAG) {
                mViewMatrix.set(mCurSavedMatrix);
                mViewMatrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix  of points
            } else if (mCurrentMode == ZOOM) {
                // pinch zooming
                float newDist = spacing(event);
                Helper.LOGD(TAG, "newDist=" + newDist);
                if (newDist > 1.f) {
                    mViewMatrix.set(mCurSavedMatrix);
                    scale = newDist / mOldDist; // setting the scaling of the
                                                // matrix...if scale > 1 means
                                                // zoom in...if scale < 1 means
                                                // zoom out
                    mViewMatrix.postScale(scale, scale, mCurMidPoint.x, mCurMidPoint.y);
                }
            }
            break;
        }
    
        view.setImageMatrix(mViewMatrix); // display the transformation on screen
    
        return true; // indicate event was handled
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////// PRIVATE SECTION ///////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // These matrices will be used to scale points of the image
    private Matrix mViewMatrix = new Matrix();
    private Matrix mCurSavedMatrix = new Matrix();
    // These PointF objects are used to record the point(s) the user is touching
    private PointF start = new PointF();
    private PointF mCurMidPoint = new PointF();
    private float mOldDist = 1f;
    
    private Matrix mMinScaleMatrix;
    private float mMinScale;
    private float mMaxScale;
    float[] mTmpValues = new float[9];
    private boolean mWasScaleTypeSet;
    
    
    /**
     * Returns scale factor of the Matrix
     * @param matrix
     * @return
     */
    private float getMatrixScale(Matrix matrix) {
        matrix.getValues(mTmpValues);
        return mTmpValues[Matrix.MSCALE_X];
    }
    
    /**
     * Downscales matrix with the scale to maximum allowed scale factor, but the same translations
     * @param scale
     * @param dist
     */
    private void downscaleMatrix(float scale, Matrix dist) {
        float resScale = mMaxScale / scale;
        dist.postScale(resScale, resScale, mCurMidPoint.x, mCurMidPoint.y);
    }
    

提交回复
热议问题