Android ImageView Zoom-in and Zoom-Out

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

    Make two java classes

    Zoom class

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.drawable.Drawable;
    import android.view.KeyEvent;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageButton;
    
    public class Zoom extends View {
    
        private Drawable image;
        ImageButton img,img1;
        private int zoomControler=20;
    
        public Zoom(Context context){
                super(context);
    
                image=context.getResources().getDrawable(R.drawable.j);
                //image=context.getResources().getDrawable(R.drawable.icon);
    
                setFocusable(true);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            //here u can control the width and height of the images........ this line is very important
            image.setBounds((getWidth()/2)-zoomControler, (getHeight()/2)-zoomControler, (getWidth()/2)+zoomControler, (getHeight()/2)+zoomControler);
            image.draw(canvas);
        }
    
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
    
                if(keyCode==KeyEvent.KEYCODE_DPAD_UP){
                        // zoom in
                        zoomControler+=10;
                }
                if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN){
                        // zoom out
                        zoomControler-=10;
                }
                if(zoomControler<10){
                        zoomControler=10;
                }
    
                invalidate();
                return true;
        }
    }
    

    make second class

    import android.app.Activity;
    import android.os.Bundle;
    
    public class Zoomexample extends Activity {
       /** Called when the activity is first created. */
    
       @Override
       public void onCreate(Bundle icicle) {
           super.onCreate(icicle);
           setContentView(new Zoom(this));
       }
    }
    
    0 讨论(0)
  • 2020-11-22 10:18

    Just change ACTION_MOVE_EVENT in Chirag Raval Answer to set ZOOM_IN LIMIT

    float[] values = new float[9]; matrix.getValues(values);
                    //0.37047964 is limit for zoom in
                    if(values[Matrix.MSCALE_X]>0.37047964) {
                        matrix.set(savedMatrix);
                        matrix.postScale(scale, scale, mid.x, mid.y);
                        view.setImageMatrix(matrix);
                    }else if (scale>1){
                        matrix.set(savedMatrix);
                        matrix.postScale(scale, scale, mid.x, mid.y);
                        view.setImageMatrix(matrix);
                    }
    
    0 讨论(0)
  • 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);
    }
    
    0 讨论(0)
  • 2020-11-22 10:20

    It's old, but this may help someone else.

    Below TouchImageView class supports both zooming in/out on either pinch or double tap

    import android.content.Context;
    import android.graphics.Matrix;
    import android.graphics.PointF;
    import android.graphics.drawable.Drawable;
    import android.util.AttributeSet;
    import android.util.Log;
    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 implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
    
        Matrix 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;
    
        int viewWidth, viewHeight;
        static final int CLICK = 3;
        float saveScale = 1f;
        protected float origWidth, origHeight;
        int oldMeasuredWidth, oldMeasuredHeight;
    
        ScaleGestureDetector mScaleDetector;
    
        Context context;
    
        public TouchImageView(Context context) {
            super(context);
            sharedConstructing(context);
        }
    
        public TouchImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            sharedConstructing(context);
        }
    
        GestureDetector mGestureDetector;
    
        private void sharedConstructing(Context context) {
            super.setClickable(true);
            this.context = context;
            mGestureDetector = new GestureDetector(context, this);
            mGestureDetector.setOnDoubleTapListener(this);
    
            mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
            matrix = new Matrix();
            m = new float[9];
            setImageMatrix(matrix);
            setScaleType(ScaleType.MATRIX);
    
            setOnTouchListener(new OnTouchListener() {
    
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    mScaleDetector.onTouchEvent(event);
                    mGestureDetector.onTouchEvent(event);
    
                    PointF curr = new PointF(event.getX(), event.getY());
    
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            last.set(curr);
                            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 fixTransX = getFixDragTrans(deltaX, viewWidth,
                                        origWidth * saveScale);
                                float fixTransY = getFixDragTrans(deltaY, viewHeight,
                                        origHeight * saveScale);
                                matrix.postTranslate(fixTransX, fixTransY);
                                fixTrans();
                                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
                }
    
            });
        }
    
        public void setMaxZoom(float x) {
            maxScale = x;
        }
    
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            return false;
        }
    
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            // Double tap is detected
            Log.i("MAIN_TAG", "Double tap detected");
            float origScale = saveScale;
            float mScaleFactor;
    
            if (saveScale == maxScale) {
                saveScale = minScale;
                mScaleFactor = minScale / origScale;
            } else {
                saveScale = maxScale;
                mScaleFactor = maxScale / origScale;
            }
    
            matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
                    viewHeight / 2);
    
            fixTrans();
            return false;
        }
    
        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            return false;
        }
    
        @Override
        public boolean onDown(MotionEvent e) {
            return false;
        }
    
        @Override
        public void onShowPress(MotionEvent e) {
    
        }
    
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }
    
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return false;
        }
    
        @Override
        public void onLongPress(MotionEvent e) {
    
        }
    
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }
    
        private class ScaleListener extends
                ScaleGestureDetector.SimpleOnScaleGestureListener {
            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                mode = ZOOM;
                return true;
            }
    
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                float mScaleFactor = detector.getScaleFactor();
                float origScale = saveScale;
                saveScale *= mScaleFactor;
                if (saveScale > maxScale) {
                    saveScale = maxScale;
                    mScaleFactor = maxScale / origScale;
                } else if (saveScale < minScale) {
                    saveScale = minScale;
                    mScaleFactor = minScale / origScale;
                }
    
                if (origWidth * saveScale <= viewWidth
                        || origHeight * saveScale <= viewHeight)
                    matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
                            viewHeight / 2);
                else
                    matrix.postScale(mScaleFactor, mScaleFactor,
                            detector.getFocusX(), detector.getFocusY());
    
                fixTrans();
                return true;
            }
        }
    
        void fixTrans() {
            matrix.getValues(m);
            float transX = m[Matrix.MTRANS_X];
            float transY = m[Matrix.MTRANS_Y];
    
            float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
            float fixTransY = getFixTrans(transY, viewHeight, origHeight
                    * saveScale);
    
            if (fixTransX != 0 || fixTransY != 0)
                matrix.postTranslate(fixTransX, fixTransY);
        }
    
        float getFixTrans(float trans, float viewSize, float contentSize) {
            float minTrans, maxTrans;
    
            if (contentSize <= viewSize) {
                minTrans = 0;
                maxTrans = viewSize - contentSize;
            } else {
                minTrans = viewSize - contentSize;
                maxTrans = 0;
            }
    
            if (trans < minTrans)
                return -trans + minTrans;
            if (trans > maxTrans)
                return -trans + maxTrans;
            return 0;
        }
    
        float getFixDragTrans(float delta, float viewSize, float contentSize) {
            if (contentSize <= viewSize) {
                return 0;
            }
            return delta;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            viewWidth = MeasureSpec.getSize(widthMeasureSpec);
            viewHeight = MeasureSpec.getSize(heightMeasureSpec);
    
            //
            // Rescales image on rotation
            //
            if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
                    || viewWidth == 0 || viewHeight == 0)
                return;
            oldMeasuredHeight = viewHeight;
            oldMeasuredWidth = viewWidth;
    
            if (saveScale == 1) {
                // Fit to screen.
                float scale;
    
                Drawable drawable = getDrawable();
                if (drawable == null || drawable.getIntrinsicWidth() == 0
                        || drawable.getIntrinsicHeight() == 0)
                    return;
                int bmWidth = drawable.getIntrinsicWidth();
                int bmHeight = drawable.getIntrinsicHeight();
    
                Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);
    
                float scaleX = (float) viewWidth / (float) bmWidth;
                float scaleY = (float) viewHeight / (float) bmHeight;
                scale = Math.min(scaleX, scaleY);
                matrix.setScale(scale, scale);
    
                // Center the image
                float redundantYSpace = (float) viewHeight
                        - (scale * (float) bmHeight);
                float redundantXSpace = (float) viewWidth
                        - (scale * (float) bmWidth);
                redundantYSpace /= (float) 2;
                redundantXSpace /= (float) 2;
    
                matrix.postTranslate(redundantXSpace, redundantYSpace);
    
                origWidth = viewWidth - 2 * redundantXSpace;
                origHeight = viewHeight - 2 * redundantYSpace;
                setImageMatrix(matrix);
            }
            fixTrans();
        }
    }
    

    Usage: You can replace your ImageView with TouchImageView in both XML & java

    1. For XML

    <?xml version="1.0" encoding="utf-8"?>
    <com.example.android.myapp.TouchImageView 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/imViewedImage"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true"
        android:focusable="true" />
    

    2. For Java

    TouchImageView imViewedImage = findViewById(R.id.imViewedImage);
    
    0 讨论(0)
  • 2020-11-22 10:20

    Method to call the About&support dialog

     public void setupAboutSupport() {
    
        try {
    
            // The About&Support AlertDialog is active
            activeAboutSupport=true;
    
            View messageView;
            int orientation=this.getResources().getConfiguration().orientation;
    
            // Inflate the about message contents
            messageView = getLayoutInflater().inflate(R.layout.about_support, null, false);
    
            ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.MyCustomTheme_AlertDialog1);
            AlertDialog.Builder builder = new AlertDialog.Builder(ctw);
            builder.setIcon(R.mipmap.ic_launcher);
            builder.setTitle(R.string.action_aboutSupport);
            builder.setView(messageView);
    
            TouchImageView imgDisplay = (TouchImageView) messageView.findViewById(R.id.action_infolinks_about_support);
            imgDisplay.setMaxZoom(3f);
    
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.myinfolinks_about_support);
    
            int imageWidth = bitmap.getWidth();
            int imageHeight = bitmap.getHeight();
            int newWidth;
    
            // Calculate the new About_Support image width
            if(orientation==Configuration.ORIENTATION_PORTRAIT ) {
                // For 7" up to 10" tablets
                //if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
                if (SingletonMyInfoLinks.isTablet) {
                        // newWidth = widthScreen - (two borders of about_support layout and 20% of width Screen)
                    newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.2));
                } else newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.1));
    
            } else {
                // For 7" up to 10" tablets
                //if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
                if (SingletonMyInfoLinks.isTablet) {
                    newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.5));
    
                } else newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.3));
            }
    
            // Get the scale factor
            float scaleFactor = (float)newWidth/(float)imageWidth;
            // Calculate the new About_Support image height
            int newHeight = (int)(imageHeight * scaleFactor);
            // Set the new bitmap corresponding the adjusted About_Support image
            bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
    
            // Rescale the image
            imgDisplay.setImageBitmap(bitmap);
    
            dialogAboutSupport = builder.show();
    
            TextView textViewVersion = (TextView) dialogAboutSupport.findViewById(R.id.action_strVersion);
            textViewVersion.setText(Html.fromHtml(getString(R.string.aboutSupport_text1)+" <b>"+versionName+"</b>"));
    
            TextView textViewDeveloperName = (TextView) dialogAboutSupport.findViewById(R.id.action_strDeveloperName);
            textViewDeveloperName.setText(Html.fromHtml(getString(R.string.aboutSupport_text2)+" <b>"+SingletonMyInfoLinks.developerName+"</b>"));
    
            TextView textViewSupportEmail = (TextView) dialogAboutSupport.findViewById(R.id.action_strSupportEmail);
            textViewSupportEmail.setText(Html.fromHtml(getString(R.string.aboutSupport_text3)+" "+SingletonMyInfoLinks.developerEmail));
    
            TextView textViewCompanyName = (TextView) dialogAboutSupport.findViewById(R.id.action_strCompanyName);
            textViewCompanyName.setText(Html.fromHtml(getString(R.string.aboutSupport_text4)+" "+SingletonMyInfoLinks.companyName));
    
            Button btnOk = (Button) dialogAboutSupport.findViewById(R.id.btnOK);
    
            btnOk.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dialogAboutSupport.dismiss();
                }
            });
    
            dialogAboutSupport.setOnDismissListener(new DialogInterface.OnDismissListener() {
                @Override
                public void onDismiss(final DialogInterface dialog) {
                    // the About & Support AlertDialog is closed
                    activeAboutSupport=false;
                }
            });
    
            dialogAboutSupport.getWindow().setBackgroundDrawable(new ColorDrawable(SingletonMyInfoLinks.atualBackgroundColor));
    
            /* Effect that image appear slower */
            // Only the fade_in matters
            AlphaAnimation fade_out = new AlphaAnimation(1.0f, 0.0f);
            AlphaAnimation fade_in = new AlphaAnimation(0.0f, 1.0f);
            AlphaAnimation a = false ? fade_out : fade_in;
    
            a.setDuration(2000); // 2 sec
            a.setFillAfter(true); // Maintain the visibility at the end of animation
            // Animation start
            ImageView img = (ImageView) messageView.findViewById(R.id.action_infolinks_about_support);
            img.startAnimation(a);
    
        } catch (Exception e) {
            //Log.e(SingletonMyInfoLinks.appNameText +"-" +  getLocalClassName() + ": ", e.getMessage());
        }
    }
    
    0 讨论(0)
  • 2020-11-22 10:20

    I think why you want to zoom-in and zoom-out the image view is because your image view is small and zooming in the image there will not let the image come out of the image view. Instead, image starts disappearing from the boundaries while zooming in. So letting the image come out of the image while we zoom in is what you want I guess.

    So there are two tricks (according to me) to achieve this-

    1. Change the layout params of the image view to cover the whole outermost view or view group at runtime while we are about to zoom-in the image.
    2. Make an expanded Image view or Full Image View (height and width = Outermost View or View Group) in xml file and set it's visibility to gone. When we are about to zoom-in the image, load the image from small Image View into full Img View, map the image in fullImgView to image in smallImgView and make it's view visible.

    Trick no.1 does not work when the image View is nested very much inside other views (like in nested recycler view)

    Trick no.2 works always :-)

    Here is the implementation of trick no.2 -

    public class ZoomOnTouchListener extends AppCompatActivity implements View.OnTouchListener {
    
        private Matrix matrix = new Matrix();
    
        private boolean isfullImgViewActive = false;
        // above boolean gets true when when we firstly move 2 fingers on the smallImgView and in this case smallImgView gets invisible and fullImgView gets visible
        // and false if smallImgView is visible and fullImgView is gone
    
        private float[] matrixArray = new float[9];
        private float orgScale;
    
        private PointF start = new PointF();
        private PointF prevP1 = new PointF();
        private PointF prevP2 = new PointF();
        private PointF mid = new PointF();
        private float oldDist = 1f;
    
        private ImageView mfullImgView;
        private ImageView smallImgView;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mfullImgView = (ImageView)findViewById(R.id.imgView2);
            mfullImgView.setVisibility(View.GONE);
            smallImgView = (ImageView)findViewById(R.id.imgView);
            smallImgView.setOnTouchListener(this);    
    
        }
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            //Log.i("0", "OnTouch()");
            if(v instanceof ImageView) {
                ImageView imgView = (ImageView) v;
    
                boolean isImgViewSmall = (imgView == smallImgView);
    
                switch (event.getAction() & MotionEvent.ACTION_MASK) {
    
                    case MotionEvent.ACTION_DOWN:   // first finger down only
    
                        //Log.i("T", "Motion Event: ACTION_DOWN");
    
                        if(isImgViewSmall)
                            start.set(event.getX(), event.getY());
    
                        prevP1.set(event.getX(), event.getY());
    
                        return true;
    
                    case MotionEvent.ACTION_POINTER_DOWN: //second finger and other fingers down
    
                        prevP1.set(event.getX(0), event.getY(0));
                        prevP2.set(event.getX(1), event.getY(1));
    
                        oldDist = spacing(event);
    
                        midPoint(mid, event);
    
                        break;
    
                    case MotionEvent.ACTION_MOVE:   //it doesn't mean fingers are moved. In this case, all pointers which are active are batched together
                                                    // this case occurs after action_down or action_pointer_down
    
                        //Log.i("Tag", event.getX()+","+event.getY());
                        if(event.getPointerCount() == 2) {
    
                            PointF newMid = new PointF();
                            midPoint(newMid,event);
    
                            float newDist = spacing(event);
    
                            float scale = newDist/oldDist;
    
                            if( !isfullImgViewActive){   // is smallImgView is visible and mfullImgView is gone
                                Log.i("tag", "true");
    
                                isfullImgViewActive = true;
    
                                matrix.set(imgView.getImageMatrix());   //note:- do not write matrix = imgView.getImageMatrix() because it gives the smallImgView's matrix reference to the matrix variable and changes on matrix will reflect on smallImgView
                                matrix.getValues(matrixArray);
    
                                orgScale = matrixArray[0];
    
                                smallImgView.setVisibility(View.INVISIBLE);
    
                                mfullImgView.setImageDrawable(smallImgView.getDrawable());
                                mfullImgView.setScaleType(ImageView.ScaleType.MATRIX);
    
                                mfullImgView.setVisibility(View.VISIBLE);
    
                                //To map the image of mFullImgView to that of smallImgView we have to 
                                // translate the mFullImgView's image
                                matrix.postTranslate(tx, ty);
                                /////////////NOTE///////////////
                                //here (tx,ty) are coordinates of top-left corner of smallimgView and 
                                // they MUST be relative to the origin of Outermost view or view group 
                                // where fullImgView is placed. So find tx,ty in your case by yourself
    
                                mfullImgView.setImageMatrix(matrix);      
                            }
    
                            if(isImgViewSmall) {
                                matrix.postScale(scale, scale, mid.x + tx, mid.y + ty);
                            }
                            else{
                                matrix.postScale(scale, scale, mid.x, mid.y);
                            }
                            oldDist = newDist;
    
                            matrix.postTranslate(newMid.x - mid.x, newMid.y - mid.y);
    
                            matrix.getValues(matrixArray);
    
                            mid.set(newMid);
    
    
                            prevP1.set(event.getX(0), event.getY(0));
                            prevP2.set(event.getX(1), event.getY(1));
    
                        }
    
                        else if(event.getPointerCount() == 1 ){
    
                            if(isfullImgViewActive) {
    
                                matrix.postTranslate(event.getX() - prevP1.x, event.getY() - prevP1.y);
                                matrix.getValues(matrixArray);
                            }
    
                            prevP1.set(event.getX(0), event.getY(0));
    
                        }
    
                        break;
    
                    case MotionEvent.ACTION_POINTER_UP: // second finger lifted
    
                        //Now if pointer of index 0 is lifted then pointer of index 1 will get index 0;
                        if(event.getActionIndex() == 0 && isfullImgViewActive){
                            Log.i("TAg", event.getActionIndex()+"");
                            prevP1.set(prevP2);
                        }
    
                        break;
    
                    case MotionEvent.ACTION_UP: // first finger lifted or all fingers are lifted
    
                        if(isImgViewSmall && !isfullImgViewActive) {
    
                            imgView.setScaleType(ImageView.ScaleType.FIT_CENTER);
    
                            int xDiff = (int) Math.abs(event.getX() - start.x);
                            int yDiff = (int) Math.abs(event.getY() - start.y);
                            if (xDiff == 0 && yDiff == 0) {
                                imgView.performClick();
                                return true;
                            }
                        }
    
                        if(isfullImgViewActive){
                            if(matrixArray[0] <= orgScale){  //matrixArray[0] is Scale.X value
    
                                mfullImgView.setOnTouchListener(null);
                                mfullImgView.setImageDrawable(null);
                                mfullImgView.setVisibility(View.GONE);
    
                                smallImgView.setOnTouchListener(this);
                                smallImgView.setScaleType(ImageView.ScaleType.FIT_CENTER);
                                smallImgView.setVisibility(View.VISIBLE);
    
                                isfullImgViewActive = false;
    
                            }
                            else if(matrixArray[0] > orgScale && isImgViewSmall){  //if the imgView was smallImgView
    
                                smallImgView.setOnTouchListener(null);
                                smallImgView.setScaleType(ImageView.ScaleType.FIT_CENTER);
                                smallImgView.setVisibility(View.GONE);  // or View.INVISIBLE
    
                                mfullImgView.setOnTouchListener(this);
                            }
                        }
    
                        return true;
    
    
                }
                //end of Switch statement
    
    
                if(isfullImgViewActive) {   //active means visible
                    mfullImgView.setImageMatrix(matrix); // display the transformation on screen
                }
    
                return true; // indicate event was handled
            }
            else
                return false;
        }
    
    
        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);
        }
    
    
        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);
        }
    
    }
    

    NOTE:- Don't set OnClickListener to mfullImgView before setting onTouchListener to it. Setting that will let the fullImageView(if it is visible) steal the touch event of putting second finger down after lifting it for the first time because we want to let the smallImgView take all the touch events until all the fingers are lifted up for the first time.

    0 讨论(0)
提交回复
热议问题