Android ImageView Zoom-in and Zoom-Out

前端 未结 23 1877
死守一世寂寞
死守一世寂寞 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:09

    Here is my solution, it is based on @alexbirkett's solution.

    public class ZoomImageView extends ImageView {
    
    // region . Static fields .
    
    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    static final int CLICK = 3;
    
    // endregion . Static fields .
    
    // region . Fields .
    
    private int mode = NONE;
    
    private Matrix mMatrix = new Matrix();
    
    private PointF mLastTouch = new PointF();
    private PointF mStartTouch = new PointF();
    private float minScale = 0.5f;
    private float maxScale = 4f;
    private float[] mCriticPoints;
    
    private float mScale = 1f;
    private float mRight;
    private float mBottom;
    private float mOriginalBitmapWidth;
    private float mOriginalBitmapHeight;
    
    private ScaleGestureDetector mScaleDetector;
    
    //endregion . Fields .
    
    // region . Ctor .
    public ZoomImageView(Context context) {
        super(context);
        init(context);
    }
    
    public ZoomImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    
    public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
    
    // endregion . Ctor .
    
    // region . Overrider .
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int bmHeight = getBmHeight();
        int bmWidth = getBmWidth();
    
        float width = getMeasuredWidth();
        float height = getMeasuredHeight();
        float scale = 1;
    
        // If image is bigger then display fit it to screen.
        if (width < bmWidth || height < bmHeight) {
            scale = width > height ? height / bmHeight : width / bmWidth;
        }
    
        mMatrix.setScale(scale, scale);
        mScale = 1f;
    
        mOriginalBitmapWidth = scale * bmWidth;
        mOriginalBitmapHeight = scale * bmHeight;
    
        // Center the image
        float redundantYSpace = (height - mOriginalBitmapHeight);
        float redundantXSpace = (width - mOriginalBitmapWidth);
    
        mMatrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);
    
        setImageMatrix(mMatrix);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mScaleDetector.onTouchEvent(event);
    
        mMatrix.getValues(mCriticPoints);
        float translateX = mCriticPoints[Matrix.MTRANS_X];
        float trnslateY = mCriticPoints[Matrix.MTRANS_Y];
        PointF currentPoint = new PointF(event.getX(), event.getY());
    
        switch (event.getAction()) {
            //when one finger is touching
            //set the mode to DRAG
            case MotionEvent.ACTION_DOWN:
                mLastTouch.set(event.getX(), event.getY());
                mStartTouch.set(mLastTouch);
                mode = DRAG;
                break;
            //when two fingers are touching
            //set the mode to ZOOM
            case MotionEvent.ACTION_POINTER_DOWN:
                mLastTouch.set(event.getX(), event.getY());
                mStartTouch.set(mLastTouch);
                mode = ZOOM;
                break;
            //when a finger moves
            //If mode is applicable move image
            case MotionEvent.ACTION_MOVE:
    
                //if the mode is ZOOM or
                //if the mode is DRAG and already zoomed
                if (mode == ZOOM || (mode == DRAG && mScale > minScale)) {
    
                    // region . Move  image.
    
                    float deltaX = currentPoint.x - mLastTouch.x;// x difference
                    float deltaY = currentPoint.y - mLastTouch.y;// y difference
                    float scaleWidth = Math.round(mOriginalBitmapWidth * mScale);// width after applying current scale
                    float scaleHeight = Math.round(mOriginalBitmapHeight * mScale);// height after applying current scale
    
                    // Move image to lef or right if its width is bigger than display width
                    if (scaleWidth > getWidth()) {
                        if (translateX + deltaX > 0) {
                            deltaX = -translateX;
                        } else if (translateX + deltaX < -mRight) {
                            deltaX = -(translateX + mRight);
                        }
                    } else {
                        deltaX = 0;
                    }
                    // Move image to up or bottom if its height is bigger than display height
                    if (scaleHeight > getHeight()) {
                        if (trnslateY + deltaY > 0) {
                            deltaY = -trnslateY;
                        } else if (trnslateY + deltaY < -mBottom) {
                            deltaY = -(trnslateY + mBottom);
                        }
                    } else {
                        deltaY = 0;
                    }
    
                    //move the image with the matrix
                    mMatrix.postTranslate(deltaX, deltaY);
                    //set the last touch location to the current
                    mLastTouch.set(currentPoint.x, currentPoint.y);
    
                    // endregion . Move image .
                }
                break;
            //first finger is lifted
            case MotionEvent.ACTION_UP:
                mode = NONE;
                int xDiff = (int) Math.abs(currentPoint.x - mStartTouch.x);
                int yDiff = (int) Math.abs(currentPoint.y - mStartTouch.y);
                if (xDiff < CLICK && yDiff < CLICK)
                    performClick();
                break;
            // second finger is lifted
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                break;
        }
        setImageMatrix(mMatrix);
        invalidate();
        return true;
    }
    
    //endregion . Overrides .
    
    // region . Privates .
    
    private void init(Context context) {
        super.setClickable(true);
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        mCriticPoints = new float[9];
        setImageMatrix(mMatrix);
        setScaleType(ScaleType.MATRIX);
    }
    
    private int getBmWidth() {
        Drawable drawable = getDrawable();
        if (drawable != null) {
            return drawable.getIntrinsicWidth();
        }
        return 0;
    }
    
    private int getBmHeight() {
        Drawable drawable = getDrawable();
        if (drawable != null) {
            return drawable.getIntrinsicHeight();
        }
        return 0;
    }
    
    //endregion . Privates .
    
    // region . Internal classes .
    
    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            mode = ZOOM;
            return true;
        }
    
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float scaleFactor = detector.getScaleFactor();
            float newScale = mScale * scaleFactor;
            if (newScale < maxScale && newScale > minScale) {
                mScale = newScale;
                float width = getWidth();
                float height = getHeight();
                mRight = (mOriginalBitmapWidth * mScale) - width;
                mBottom = (mOriginalBitmapHeight * mScale) - height;
    
                float scaledBitmapWidth = mOriginalBitmapWidth * mScale;
                float scaledBitmapHeight = mOriginalBitmapHeight * mScale;
    
                if (scaledBitmapWidth <= width || scaledBitmapHeight <= height) {
                    mMatrix.postScale(scaleFactor, scaleFactor, width / 2, height / 2);
                } else {
                    mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
                }
            }
            return true;
        }
    }
    
    // endregion . Internal classes .
    }
    
    0 讨论(0)
  • 2020-11-22 10:11

    just use this class : TouchImageView

    0 讨论(0)
  • 2020-11-22 10:14

    Step 1: First you add dependencies in build.gradle(Module:app) file.

    dependencies {
    
         implementation 'com.jsibbold:zoomage:1.2.0'
    
        }
    

    Step 2: Next create a class

    ImageFullScreenFragment.java

    public class ImageFullScreenFragment{
    
       private ZoomageView ImageZoomageView;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View view = null;
    
          try {
             view = inflater.inflate(R.layout.fragment_image_full_screen, container, false);
                ImageZoomageView = view.findViewById(R.id.imageViewImageFullScreen);
                ImageZoomageView.setImageResource(R.drawable.image);
    
             } catch (Exception e) {
                 e.printStackTrace();
             }
        return view;
    
    }
    

    Step 3 : Next create a layout xml file

    fragment_image_full_screen.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <com.jsibbold.zoomage.ZoomageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:zoomage_restrictBounds="false"
            app:zoomage_animateOnReset="true"
            app:zoomage_autoResetMode="UNDER"
            app:zoomage_autoCenter="true"
            app:zoomage_zoomable="true"
            app:zoomage_translatable="true"
            app:zoomage_minScale="0.6"
            app:zoomage_maxScale="8"
            android:id="@+id/imageViewImageFullScreen"
            />
    
    </RelativeLayout>
    

    OutPut:-

    0 讨论(0)
  • 2020-11-22 10:15

    Please follow the below class, that is used for Zoom in and Zoom Out for ImageView.

    import android.app.Activity;
    import android.graphics.Matrix;
    import android.graphics.PointF;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnTouchListener;
    import android.widget.ImageView;
    
    public class ZoomInZoomOut extends Activity implements OnTouchListener 
    {
        private static final String TAG = "Touch";
        @SuppressWarnings("unused")
        private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f;
    
        // These matrices will be used to scale points of the image
        Matrix matrix = new Matrix();
        Matrix savedMatrix = new Matrix();
    
        // The 3 states (events) which the user is trying to perform
        static final int NONE = 0;
        static final int DRAG = 1;
        static final int ZOOM = 2;
        int mode = NONE;
    
        // these PointF objects are used to record the point(s) the user is touching
        PointF start = new PointF();
        PointF mid = new PointF();
        float oldDist = 1f;
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) 
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            ImageView view = (ImageView) findViewById(R.id.imageView);
            view.setOnTouchListener(this);
        }
    
        @Override
        public boolean onTouch(View v, MotionEvent event) 
        {
            ImageView view = (ImageView) v;
            view.setScaleType(ImageView.ScaleType.MATRIX);
            float scale;
    
            dumpEvent(event);
            // Handle touch events here...
    
            switch (event.getAction() & MotionEvent.ACTION_MASK) 
            {
                case MotionEvent.ACTION_DOWN:   // first finger down only
                                                    savedMatrix.set(matrix);
                                                    start.set(event.getX(), event.getY());
                                                    Log.d(TAG, "mode=DRAG"); // write to LogCat
                                                    mode = DRAG;
                                                    break;
    
                case MotionEvent.ACTION_UP: // first finger lifted
    
                case MotionEvent.ACTION_POINTER_UP: // second finger lifted
    
                                                    mode = NONE;
                                                    Log.d(TAG, "mode=NONE");
                                                    break;
    
                case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
    
                                                    oldDist = spacing(event);
                                                    Log.d(TAG, "oldDist=" + oldDist);
                                                    if (oldDist > 5f) {
                                                        savedMatrix.set(matrix);
                                                        midPoint(mid, event);
                                                        mode = ZOOM;
                                                        Log.d(TAG, "mode=ZOOM");
                                                    }
                                                    break;
    
                case MotionEvent.ACTION_MOVE:
    
                                                    if (mode == DRAG) 
                                                    { 
                                                        matrix.set(savedMatrix);
                                                        matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix  of points
                                                    } 
                                                    else if (mode == ZOOM) 
                                                    { 
                                                        // pinch zooming
                                                        float newDist = spacing(event);
                                                        Log.d(TAG, "newDist=" + newDist);
                                                        if (newDist > 5f) 
                                                        {
                                                            matrix.set(savedMatrix);
                                                            scale = newDist / oldDist; // setting the scaling of the
                                                                                        // matrix...if scale > 1 means
                                                                                        // zoom in...if scale < 1 means
                                                                                        // zoom out
                                                            matrix.postScale(scale, scale, mid.x, mid.y);
                                                        }
                                                    }
                                                    break;
            }
    
            view.setImageMatrix(matrix); // display the transformation on screen
    
            return true; // indicate event was handled
        }
    
        /*
         * --------------------------------------------------------------------------
         * Method: spacing Parameters: MotionEvent Returns: float Description:
         * checks the spacing between the two fingers on touch
         * ----------------------------------------------------
         */
    
        private float spacing(MotionEvent event) 
        {
            float x = event.getX(0) - event.getX(1);
            float y = event.getY(0) - event.getY(1);
            return (float) Math.sqrt(x * x + y * y);
        }
    
        /*
         * --------------------------------------------------------------------------
         * Method: midPoint Parameters: PointF object, MotionEvent Returns: void
         * Description: calculates the midpoint between the two fingers
         * ------------------------------------------------------------
         */
    
        private void midPoint(PointF point, MotionEvent event) 
        {
            float x = event.getX(0) + event.getX(1);
            float y = event.getY(0) + event.getY(1);
            point.set(x / 2, y / 2);
        }
    
        /** Show an event in the LogCat view, for debugging */
        private void dumpEvent(MotionEvent event) 
        {
            String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE","POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
            StringBuilder sb = new StringBuilder();
            int action = event.getAction();
            int actionCode = action & MotionEvent.ACTION_MASK;
            sb.append("event ACTION_").append(names[actionCode]);
    
            if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) 
            {
                sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
                sb.append(")");
            }
    
            sb.append("[");
            for (int i = 0; i < event.getPointerCount(); i++) 
            {
                sb.append("#").append(i);
                sb.append("(pid ").append(event.getPointerId(i));
                sb.append(")=").append((int) event.getX(i));
                sb.append(",").append((int) event.getY(i));
                if (i + 1 < event.getPointerCount())
                    sb.append(";");
            }
    
            sb.append("]");
            Log.d("Touch Events ---------", sb.toString());
        }
    }
    
    0 讨论(0)
  • 2020-11-22 10:15

    I know it is a bit late for this answer, but I hope it helps someone.

    I was looking for the same thing (Zoom using pinch, and dragging image) and I found this Android Developers Blog link.

    Works perfect. No artifacts or what so ever. It uses ScaleGestureDetector.

    0 讨论(0)
  • 2020-11-22 10:15

    I am Using this one it is working perfectly.

    <your.packagename.MyZoomableImageViewTouch
            android:id="@+id/mediaImage"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:scaleType="matrix"/>
    

    My a MyZoomableImageViewTouch class is below:

    public class MyZoomableImageViewTouch extends ImageViewTouch
    {
    
        static final float SCROLL_DELTA_THRESHOLD = 1.0f;
    
        public MyZoomableImageViewTouch(Context context, AttributeSet attrs, int defStyle)
        {
            super(context, attrs, defStyle);
            init();
        }
    
        public MyZoomableImageViewTouch(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public MyZoomableImageViewTouch(Context context)
        {
            super(context);
            init();
        }
    
        private void init() {
            View.OnTouchListener listener = new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (getScale() > 1f) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    } else {
                        getParent().requestDisallowInterceptTouchEvent(false);
                    }
                    return false;
                }
            };
            setOnTouchListener(listener);
            setDisplayType(DisplayType.FIT_TO_SCREEN);
        }
    
        @Override
        protected float onDoubleTapPost(float scale, float maxZoom) {
            if (scale != 1f) {
                mDoubleTapDirection = 1;
                return 1f;
            }
            if (mDoubleTapDirection == 1) {
                mDoubleTapDirection = -1;
                if ((scale + (mScaleFactor * 2)) <= maxZoom) {
                    return scale + mScaleFactor;
                } else {
                    mDoubleTapDirection = -1;
                    return maxZoom;
                }
            } else {
                mDoubleTapDirection = 1;
                return 1f;
            }
        }
    
        @Override
        public boolean canScroll(int direction) {
            RectF bitmapRect = getBitmapRect();
            updateRect(bitmapRect, mScrollRect);
            Rect imageViewRect = new Rect();
            getGlobalVisibleRect(imageViewRect);
    
            if (null == bitmapRect) {
                return false;
            }
    
            if (Math.abs(bitmapRect.right - imageViewRect.right) < SCROLL_DELTA_THRESHOLD) {
                if (direction < 0) {
                    return false;
                }
            }
    
            if (Math.abs(bitmapRect.left - mScrollRect.left) < SCROLL_DELTA_THRESHOLD) {
                if (direction > 0) {
                    return false;
                }
            }
            return true;
        }
    
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
        {
            if (getScale() == 1f) return false;
            if (distanceX != 0 && !canScroll((int) -distanceX)) {
                getParent().requestDisallowInterceptTouchEvent(false);
                return false;
            } else {
                getParent().requestDisallowInterceptTouchEvent(true);
                mUserScaled = true;
                scrollBy(-distanceX, -distanceY);
                invalidate();
                return true;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题