zoukankan      html  css  js  c++  java
  • Android 手势滑动,多点触摸放大缩小图片

    学习安卓两点触摸滑动缩放图片

    1.布局文件如下main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
      <!-- 引用自定义控件 --> <com.ymw.zoomimage.ZoomImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" > </com.ymw.zoomimage.ZoomImageView> </LinearLayout>

    2.自定义缩放图片控件ZoomImageView.java代码:

    package com.ymw.zoomimage;
    
    import java.util.Observable;
    import java.util.Observer;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    public class ZoomImageView extends View implements Observer {
    
        /** Paint object used when drawing bitmap. */
        private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
    
        /** Rectangle used (and re-used) for cropping source image. */
        private final Rect mRectSrc = new Rect();
    
        /** Rectangle used (and re-used) for specifying drawing area on canvas. */
        private final Rect mRectDst = new Rect();
    
        /** Object holding aspect quotient */
        private final AspectQuotient mAspectQuotient = new AspectQuotient();
    
        /** The bitmap that we're zooming in, and drawing on the screen. */
        private Bitmap mBitmap;
    
        /** State of the zoom. */
        private ZoomState mState;
    
        private BasicZoomControl mZoomControl;
        private BasicZoomListener mZoomListener;
    
        public ZoomImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            mZoomControl = new BasicZoomControl();
    
            mZoomListener = new BasicZoomListener();
            mZoomListener.setZoomControl(mZoomControl);
    
            setZoomState(mZoomControl.getZoomState());
    
            setOnTouchListener(mZoomListener);
    
            mZoomControl.setAspectQuotient(getAspectQuotient());
        }
    
        public void zoomImage(float f, float x, float y) {
            mZoomControl.zoom(f, x, y);
        }
    
        public void setImage(Bitmap bitmap) {
            mBitmap = bitmap;
    
            mAspectQuotient.updateAspectQuotient(getWidth(), getHeight(),
                    mBitmap.getWidth(), mBitmap.getHeight());
            mAspectQuotient.notifyObservers();
    
            invalidate();
        }
    
        private void setZoomState(ZoomState state) {
            if (mState != null) {
                mState.deleteObserver(this);
            }
    
            mState = state;
            mState.addObserver(this);
    
            invalidate();
        }
    
        private AspectQuotient getAspectQuotient() {
            return mAspectQuotient;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if (mBitmap != null && mState != null) {
    
                Log.d("ZoomImageView", "OnDraw");
    
                final float aspectQuotient = mAspectQuotient.get();
    
                final int viewWidth = getWidth();
                final int viewHeight = getHeight();
                final int bitmapWidth = mBitmap.getWidth();
                final int bitmapHeight = mBitmap.getHeight();
    
                Log.d("ZoomImageView", "viewWidth = " + viewWidth);
                Log.d("ZoomImageView", "viewHeight = " + viewHeight);
                Log.d("ZoomImageView", "bitmapWidth = " + bitmapWidth);
                Log.d("ZoomImageView", "bitmapHeight = " + bitmapHeight);
    
                final float panX = mState.getPanX();
                final float panY = mState.getPanY();
                final float zoomX = mState.getZoomX(aspectQuotient) * viewWidth
                        / bitmapWidth;
                final float zoomY = mState.getZoomY(aspectQuotient) * viewHeight
                        / bitmapHeight;
    
                // Setup source and destination rectangles
                mRectSrc.left = (int) (panX * bitmapWidth - viewWidth / (zoomX * 2));
                mRectSrc.top = (int) (panY * bitmapHeight - viewHeight
                        / (zoomY * 2));
                mRectSrc.right = (int) (mRectSrc.left + viewWidth / zoomX);
                mRectSrc.bottom = (int) (mRectSrc.top + viewHeight / zoomY);
                // mRectDst.left = getLeft();
                mRectDst.left = 0;
                mRectDst.top = 0;
                // mRectDst.right = getRight();
                mRectDst.right = getWidth();
                mRectDst.bottom = getHeight();
    
                // Adjust source rectangle so that it fits within the source image.
                if (mRectSrc.left < 0) {
                    mRectDst.left += -mRectSrc.left * zoomX;
                    mRectSrc.left = 0;
                }
                if (mRectSrc.right > bitmapWidth) {
                    mRectDst.right -= (mRectSrc.right - bitmapWidth) * zoomX;
                    mRectSrc.right = bitmapWidth;
                }
                if (mRectSrc.top < 0) {
                    mRectDst.top += -mRectSrc.top * zoomY;
                    mRectSrc.top = 0;
                }
                if (mRectSrc.bottom > bitmapHeight) {
                    mRectDst.bottom -= (mRectSrc.bottom - bitmapHeight) * zoomY;
                    mRectSrc.bottom = bitmapHeight;
                }
    
                mRectDst.left = 0;
                mRectDst.top = 0;
                mRectDst.right = viewWidth;
                mRectDst.bottom = viewHeight;
    
                Log.d("ZoomImageView", "mRectSrc.top" + mRectSrc.top);
                Log.d("ZoomImageView", "mRectSrc.bottom" + mRectSrc.bottom);
                Log.d("ZoomImageView", "mRectSrc.left" + mRectSrc.left);
                Log.d("ZoomImageView", "mRectSrc.right" + mRectSrc.right);
    
                Log.d("ZoomImageView", "mRectDst.top" + mRectDst.top);
                Log.d("ZoomImageView", "mRectDst.bottom" + mRectDst.bottom);
                Log.d("ZoomImageView", "mRectDst.left" + mRectDst.left);
                Log.d("ZoomImageView", "mRectDst.right" + mRectDst.right);
    
                canvas.drawBitmap(mBitmap, mRectSrc, mRectDst, mPaint);
            }
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right,
                int bottom) {
            super.onLayout(changed, left, top, right, bottom);
    
            mAspectQuotient.updateAspectQuotient(right - left, bottom - top,
                    mBitmap.getWidth(), mBitmap.getHeight());
            mAspectQuotient.notifyObservers();
        }
    
        @Override
        public void update(Observable observable, Object data) {
            invalidate();
        }
    
        private class BasicZoomListener implements View.OnTouchListener {
    
            /** Zoom control to manipulate */
            private BasicZoomControl mZoomControl;
    
            private float mFirstX = -1;
            private float mFirstY = -1;
            private float mSecondX = -1;
            private float mSecondY = -1;
    
            private int mOldCounts = 0;
    
            /**
             * Sets the zoom control to manipulate
             * 
             * @param control
             *            Zoom control
             */
            public void setZoomControl(BasicZoomControl control) {
                mZoomControl = control;
            }
    
            public boolean onTouch(View v, MotionEvent event) {
    
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mOldCounts = 1;
                    mFirstX = event.getX();
                    mFirstY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE: {
                    float fFirstX = event.getX();
                    float fFirstY = event.getY();
    
                    int nCounts = event.getPointerCount();
    
                    if (1 == nCounts) {
                        mOldCounts = 1;
                        float dx = (fFirstX - mFirstX) / v.getWidth();
                        float dy = (fFirstY - mFirstY) / v.getHeight();
                        mZoomControl.pan(-dx, -dy);
                    } else if (1 == mOldCounts) {
                        mSecondX = event.getX(event.getPointerId(nCounts - 1));
                        mSecondY = event.getY(event.getPointerId(nCounts - 1));
                        mOldCounts = nCounts;
                    } else {
                        float fSecondX = event
                                .getX(event.getPointerId(nCounts - 1));
                        float fSecondY = event
                                .getY(event.getPointerId(nCounts - 1));
    
                        double nLengthOld = getLength(mFirstX, mFirstY, mSecondX,
                                mSecondY);
                        double nLengthNow = getLength(fFirstX, fFirstY, fSecondX,
                                fSecondY);
    
                        float d = (float) ((nLengthNow - nLengthOld) / v.getWidth());
    
                        mZoomControl.zoom((float) Math.pow(20, d),
                                ((fFirstX + fSecondX) / 2 / v.getWidth()),
                                ((fFirstY + fSecondY) / 2 / v.getHeight()));
    
                        mSecondX = fSecondX;
                        mSecondY = fSecondY;
                    }
                    mFirstX = fFirstX;
                    mFirstY = fFirstY;
    
                    break;
                }
    
                }
    
                return true;
            }
    
            private double getLength(float x1, float y1, float x2, float y2) {
                return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
            }
        }
    
        private class BasicZoomControl implements Observer {
    
            /** Minimum zoom level limit */
            private static final float MIN_ZOOM = 1;
    
            /** Maximum zoom level limit */
            private static final float MAX_ZOOM = 16;
    
            /** Zoom state under control */
            private final ZoomState mState = new ZoomState();
    
            /** Object holding aspect quotient of view and content */
            private AspectQuotient mAspectQuotient;
    
            /**
             * Set reference object holding aspect quotient
             * 
             * @param aspectQuotient
             *            Object holding aspect quotient
             */
            public void setAspectQuotient(AspectQuotient aspectQuotient) {
                if (mAspectQuotient != null) {
                    mAspectQuotient.deleteObserver(this);
                }
    
                mAspectQuotient = aspectQuotient;
                mAspectQuotient.addObserver(this);
            }
    
            /**
             * Get zoom state being controlled
             * 
             * @return The zoom state
             */
            public ZoomState getZoomState() {
                return mState;
            }
    
            /**
             * Zoom
             * 
             * @param f
             *            Factor of zoom to apply
             * @param x
             *            X-coordinate of invariant position
             * @param y
             *            Y-coordinate of invariant position
             */
            public void zoom(float f, float x, float y) {
    
                // Log.d("Zoom", "zoom f = " + f);
    
                final float aspectQuotient = mAspectQuotient.get();
    
                final float prevZoomX = mState.getZoomX(aspectQuotient);
                final float prevZoomY = mState.getZoomY(aspectQuotient);
    
                mState.setZoom(mState.getZoom() * f);
                limitZoom();
    
                final float newZoomX = mState.getZoomX(aspectQuotient);
                final float newZoomY = mState.getZoomY(aspectQuotient);
    
                // Pan to keep x and y coordinate invariant
                mState.setPanX(mState.getPanX() + (x - .5f)
                        * (1f / prevZoomX - 1f / newZoomX));
                mState.setPanY(mState.getPanY() + (y - .5f)
                        * (1f / prevZoomY - 1f / newZoomY));
    
                limitPan();
    
                mState.notifyObservers();
            }
    
            /**
             * Pan
             * 
             * @param dx
             *            Amount to pan in x-dimension
             * @param dy
             *            Amount to pan in y-dimension
             */
            public void pan(float dx, float dy) {
                final float aspectQuotient = mAspectQuotient.get();
    
                mState.setPanX(mState.getPanX() + dx
                        / mState.getZoomX(aspectQuotient));
                mState.setPanY(mState.getPanY() + dy
                        / mState.getZoomY(aspectQuotient));
    
                limitPan();
    
                mState.notifyObservers();
            }
    
            /**
             * Help function to figure out max delta of pan from center position.
             * 
             * @param zoom
             *            Zoom value
             * @return Max delta of pan
             */
            private float getMaxPanDelta(float zoom) {
                return Math.max(0f, .5f * ((zoom - 1) / zoom));
            }
    
            /**
             * Force zoom to stay within limits
             */
            private void limitZoom() {
                if (mState.getZoom() < MIN_ZOOM) {
                    mState.setZoom(MIN_ZOOM);
                } else if (mState.getZoom() > MAX_ZOOM) {
                    mState.setZoom(MAX_ZOOM);
                }
            }
    
            /**
             * Force pan to stay within limits
             */
            private void limitPan() {
                final float aspectQuotient = mAspectQuotient.get();
    
                final float zoomX = mState.getZoomX(aspectQuotient);
                final float zoomY = mState.getZoomY(aspectQuotient);
    
                final float panMinX = .5f - getMaxPanDelta(zoomX);
                final float panMaxX = .5f + getMaxPanDelta(zoomX);
                final float panMinY = .5f - getMaxPanDelta(zoomY);
                final float panMaxY = .5f + getMaxPanDelta(zoomY);
    
                if (mState.getPanX() < panMinX) {
                    mState.setPanX(panMinX);
                }
                if (mState.getPanX() > panMaxX) {
                    mState.setPanX(panMaxX);
                }
                if (mState.getPanY() < panMinY) {
                    mState.setPanY(panMinY);
                }
                if (mState.getPanY() > panMaxY) {
                    mState.setPanY(panMaxY);
                }
            }
    
            // Observable interface implementation
    
            public void update(Observable observable, Object data) {
                limitZoom();
                limitPan();
            }
        }
    
        private class AspectQuotient extends Observable {
    
            /**
             * Aspect quotient
             */
            private float mAspectQuotient;
    
            // Public methods
    
            /**
             * Gets aspect quotient
             * 
             * @return The aspect quotient
             */
            public float get() {
                return mAspectQuotient;
            }
    
            /**
             * Updates and recalculates aspect quotient based on supplied view and
             * content dimensions.
             * 
             * @param viewWidth
             *            Width of view
             * @param viewHeight
             *            Height of view
             * @param contentWidth
             *            Width of content
             * @param contentHeight
             *            Height of content
             */
            public void updateAspectQuotient(float viewWidth, float viewHeight,
                    float contentWidth, float contentHeight) {
                final float aspectQuotient = (contentWidth / contentHeight)
                        / (viewWidth / viewHeight);
    
                if (aspectQuotient != mAspectQuotient) {
                    mAspectQuotient = aspectQuotient;
                    setChanged();
                }
            }
        }
    
        private class ZoomState extends Observable {
            /**
             * Zoom level A value of 1.0 means the content fits the view.
             */
            private float mZoom;
    
            /**
             * Pan position x-coordinate X-coordinate of zoom window center
             * position, relative to the width of the content.
             */
            private float mPanX;
    
            /**
             * Pan position y-coordinate Y-coordinate of zoom window center
             * position, relative to the height of the content.
             */
            private float mPanY;
    
            // Public methods
    
            /**
             * Get current x-pan
             * 
             * @return current x-pan
             */
            public float getPanX() {
                return mPanX;
            }
    
            /**
             * Get current y-pan
             * 
             * @return Current y-pan
             */
            public float getPanY() {
                return mPanY;
            }
    
            /**
             * Get current zoom value
             * 
             * @return Current zoom value
             */
            public float getZoom() {
                return mZoom;
            }
    
            /**
             * Help function for calculating current zoom value in x-dimension
             * 
             * @param aspectQuotient
             *            (Aspect ratio content) / (Aspect ratio view)
             * @return Current zoom value in x-dimension
             */
            public float getZoomX(float aspectQuotient) {
                return Math.min(mZoom, mZoom * aspectQuotient);
            }
    
            /**
             * Help function for calculating current zoom value in y-dimension
             * 
             * @param aspectQuotient
             *            (Aspect ratio content) / (Aspect ratio view)
             * @return Current zoom value in y-dimension
             */
            public float getZoomY(float aspectQuotient) {
                return Math.min(mZoom, mZoom / aspectQuotient);
            }
    
            /**
             * Set pan-x
             * 
             * @param panX
             *            Pan-x value to set
             */
            public void setPanX(float panX) {
                if (panX != mPanX) {
                    mPanX = panX;
                    setChanged();
                }
            }
    
            /**
             * Set pan-y
             * 
             * @param panY
             *            Pan-y value to set
             */
            public void setPanY(float panY) {
                if (panY != mPanY) {
                    mPanY = panY;
                    setChanged();
                }
            }
    
            /**
             * Set zoom
             * 
             * @param zoom
             *            Zoom value to set
             */
            public void setZoom(float zoom) {
                if (zoom != mZoom) {
                    mZoom = zoom;
                    setChanged();
                }
            }
        }
    }
    View Code

    3.工程主文件MainActivity.java代码:

    package com.ymw.zoomimage;
    
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Bundle;
    
    public class MainActivity extends Activity {
    
        private ZoomImageView zoomImg;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            zoomImg = (ZoomImageView) findViewById(R.id.image);
            Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(),
                    R.drawable.a);
            zoomImg.setImage(bitmap);
    
        }
    }

    4.实例项目链接如下:

    http://pan.baidu.com/s/1pJ7HWSj

  • 相关阅读:
    12月11日
    081212 晴
    12月10日
    树莓派项目——基于树莓派的WIFI网络互传系统设计
    IDE
    边缘检测
    Android Launcher桌面应用快捷方式的开发
    android ui事件处理分析
    listview 分析
    ApplicationsIntentReceiver.class
  • 原文地址:https://www.cnblogs.com/_ymw/p/4156577.html
Copyright © 2011-2022 走看看