通過手勢實現Android ImageView 縮放

jopen 10年前發布 | 53K 次閱讀 Android Android開發 移動開發


方法一:

將以下代碼寫到MulitPointTouchListener.java中,然后對你相應的圖片進行OnTouchListener。
例如:imageView.setOnTouchListener(new MulitPointTouchListener ());

在xml中要將ImageView的縮放格式改成Matrix

例如:android:scaleType="matrix"

這樣就可以實現圖片的縮放了

 

下面是MulitPointTouchListener.java代碼:

public class MulitPointTouchListener implements OnTouchListener {   
        private static final String TAG = "Touch";   
        // These matrices will be used to move and zoom image   
        Matrix matrix = new Matrix();   
        Matrix savedMatrix = 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 start = new PointF();   
        PointF mid = new PointF();   
        float oldDist = 1f;   

        @Override  
        public boolean onTouch(View v, MotionEvent event) {   

                ImageView view = (ImageView) v;   
                // Log.e("view_width",   
                // view.getImageMatrix()..toString()+"*"+v.getWidth());   
                // Dump touch event to log   
                dumpEvent(event);   

                // Handle touch events here...   
                switch (event.getAction() & MotionEvent.ACTION_MASK) {   
                case MotionEvent.ACTION_DOWN:   

                        matrix.set(view.getImageMatrix());   
                        savedMatrix.set(matrix);   
                        start.set(event.getX(), event.getY());   
                        //Log.d(TAG, "mode=DRAG");   
                        mode = DRAG;   


                        //Log.d(TAG, "mode=NONE");   
                        break;   
                case MotionEvent.ACTION_POINTER_DOWN:   
                        oldDist = spacing(event);   
                        //Log.d(TAG, "oldDist=" + oldDist);   
                        if (oldDist > 10f) {   
                                savedMatrix.set(matrix);   
                                midPoint(mid, event);   
                                mode = ZOOM;   
                                //Log.d(TAG, "mode=ZOOM");   
                        }   
                        break;   
                case MotionEvent.ACTION_UP:   
                case MotionEvent.ACTION_POINTER_UP:   
                        mode = NONE;   
                        //Log.e("view.getWidth", view.getWidth() + "");   
                        //Log.e("view.getHeight", view.getHeight() + "");   

                        break;   
                case MotionEvent.ACTION_MOVE:   
                        if (mode == DRAG) {   
                                // ...   
                                matrix.set(savedMatrix);   
                                matrix.postTranslate(event.getX() - start.x, event.getY()   
                                                - start.y);   
                        } else if (mode == ZOOM) {   
                                float newDist = spacing(event);   
                                //Log.d(TAG, "newDist=" + newDist);   
                                if (newDist > 10f) {   
                                        matrix.set(savedMatrix);   
                                        float scale = newDist / oldDist;   
                                        matrix.postScale(scale, scale, mid.x, mid.y);   
                                }   
                        }   
                        break;   
                }   

                view.setImageMatrix(matrix);   
                return true; // indicate event was handled   
        }   

        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(TAG, sb.toString());   
        }   


        private float spacing(MotionEvent event) {   
                float x = event.getX(0) - event.getX(1);   
                float y = event.getY(0) - event.getY(1);   
                return FloatMath.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);   
        }   
}  

 

方法二:自定義一個ImageView,例如TouchImageView:

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.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;

public class TouchImageView extends ImageView {

    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);
    }

    private void sharedConstructing(Context context) {
        super.setClickable(true);
        this.context = context;
        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);
                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;
    }

    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();
    }
}

然后在我們的Activity中就可以直接使用了:

public class TouchImageViewActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TouchImageView img = (TouchImageView) findViewById(R.id.snoop);
        img.setImageResource(R.drawable.snoopy);
        img.setMaxZoom(4f);
    }
}



 

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!