zoukankan      html  css  js  c++  java
  • Android-相册效果(图片缩放 自由滑动)

    先上图:

    很多时候 我们会有这么一个需求:

    展示一组图片 每个Item的图片 可以自由拉伸 滑动 焦点不冲突

    网上有很多实现方法 通过自定义Gallery和ImageView来实现

    个人不是很推荐 在这里推荐有ViewPager加ZoomImageView

    ViewPager就不过多解释 主要是ZoomImageView

    上代码:

    public class ZoomImageView extends ImageView implements OnTouchListener, OnGestureListener{
        private int WIDTH;
        private int HEIGHT;
        private int mStatusHeight;
        
        private static final String TAG = ZoomImageView.class.getSimpleName();
    
        // This is the base transformation which is used to show the image
        // initially. The current computation for this shows the image in
        // it's entirety, letterboxing as needed. One could choose to
        // show the image as cropped instead.
        //
        // This matrix is recomputed when we go from the thumbnail image to
        // the full size image.
        protected Matrix mBaseMatrix = new Matrix();
    
        // This is the supplementary transformation which reflects what
        // the user has done in terms of zooming and panning.
        //
        // This matrix reHonagAnGalleryActivitys the same when we go from the
        // thumbnail image
        // to the full size image.
        protected Matrix mSuppMatrix = new Matrix();
    
        // This is the final matrix which is computed as the concatentation
        // of the base matrix and the supplementary matrix.
        private final Matrix mDisplayMatrix = new Matrix();
    
        // Temporary buffer used for getting the values out of a matrix.
        private final float[] mMatrixValues = new float[9];
    
        // The current bitmap being displayed.
        // protected final RotateBitmap mBitmapDisplayed = new RotateBitmap(null);
        protected Bitmap image = null;
    
        int mThisWidth = -1, mThisHeight = -1;
    
        float mMaxZoom = 4.0f;
        float mMinZoom = 0.1f;
    
        private int imageWidth;
        private int imageHeight;
    
        private float scaleRate;
    
        public ZoomImageView(Context context) {
            super(context);
            init();
        }
    
        public ZoomImageView(Context context, int imageWidth, int imageHeight) {
            super(context);
            this.imageHeight = imageHeight;
            this.imageWidth = imageWidth;
            init();
        }
    
        public ZoomImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        private void arithScaleRate() {
            float scaleWidth = WIDTH / (float) imageWidth;
            float scaleHeight = HEIGHT / (float) imageHeight;
            scaleRate = Math.min(scaleWidth, scaleHeight);
            if (scaleRate > 1) {
                scaleRate = 1f;
            }
        }
    
        public float getScaleRate() {
            return scaleRate;
        }
    
        public int getImageWidth() {
            return imageWidth;
        }
    
        public void setImageWidth(int imageWidth) {
            this.imageWidth = imageWidth;
        }
    
        public int getImageHeight() {
            return imageHeight;
        }
    
        public void setImageHeight(int imageHeight) {
            this.imageHeight = imageHeight;
        }
    
        protected Handler mHandler = new Handler();
    
        @Override
        public void setImageResource(int resId) {
            Bitmap bit = BitmapFactory.decodeResource(getResources(), resId);
            setImageBitmap(bit);
        }
    
        @Override
        public void setImageBitmap(Bitmap bitmap) {
            super.setImageBitmap(bitmap);
            this.imageHeight = bitmap.getHeight();
            this.imageWidth = bitmap.getWidth();
            image = bitmap;
            requestImage();
        }
    
        public void requestImage() {
            arithScaleRate();
            zoomTo(scaleRate, WIDTH / 2f, WIDTH / 2f);
            layoutToCenter();
        }
    
        // Center as much as possible in one or both axis. Centering is
        // defined as follows: if the image is scaled down below the
        // view's dimensions then center it (literally). If the image
        // is scaled larger than the view and is translated out of view
        // then translate it back into view (i.e. eliminate black bars).
        protected void center(boolean horizontal, boolean vertical) {
            // if (mBitmapDisplayed.getBitmap() == null) {
            // return;
            // }
            if (image == null) {
                return;
            }
    
            Matrix m = getImageViewMatrix();
    
            RectF rect = new RectF(0, 0, image.getWidth(), image.getHeight());
            // RectF rect = new RectF(0, 0, imageWidth*getScale(),
            // imageHeight*getScale());
    
            m.mapRect(rect);
    
            float height = rect.height();
            float width = rect.width();
    
            float deltaX = 0, deltaY = 0;
    
            if (vertical) {
                int viewHeight = getHeight();
                if (height < viewHeight) {
                    deltaY = (viewHeight - height) / 2 - rect.top;
                } else if (rect.top > 0) {
                    deltaY = -rect.top;
                } else if (rect.bottom < viewHeight) {
                    deltaY = getHeight() - rect.bottom;
                }
            }
    
            if (horizontal) {
                int viewWidth = getWidth();
                if (width < viewWidth) {
                    deltaX = (viewWidth - width) / 2 - rect.left;
                } else if (rect.left > 0) {
                    deltaX = -rect.left;
                } else if (rect.right < viewWidth) {
                    deltaX = viewWidth - rect.right;
                }
            }
            postTranslate(deltaX, deltaY);
            setImageMatrix(getImageViewMatrix());
        }
        
        public void setStatusHeight(int height) {
            HEIGHT -= height;
        }
    
        private void init() {
            // except the height of the top bar
            DisplayMetrics dm = getResources().getDisplayMetrics();
            WIDTH = dm.widthPixels;
            HEIGHT = dm.heightPixels;
            
    //        HEIGHT -= getResources().getDimension(R.dimen.top_bar_height);
            setScaleType(ImageView.ScaleType.MATRIX);
            setOnTouchListener(this);
            
            mDetector = new GestureDetector(getContext(), this);
        }
    
        public void layoutToCenter() {
            float width = imageWidth * getScale();
            float height = imageHeight * getScale();
    
            float fill_width = WIDTH - width;
            float fill_height = HEIGHT - height;
    
            float tran_width = 0f;
            float tran_height = 0f;
    
            if (fill_width > 0)
                tran_width = fill_width / 2;
            if (fill_height > 0)
                tran_height = fill_height / 2;
    
            float v[] = new float[9];
            Matrix m = getImageMatrix();
            m.getValues(v);
            float left = v[Matrix.MTRANS_X];
            float top = v[Matrix.MTRANS_Y];
    
            tran_width -= left;
            tran_height -= top;
    
            postTranslate(tran_width, tran_height);
            // setImageMatrix(getImageViewMatrix());
        }
    
        protected float getValue(Matrix matrix, int whichValue) {
            matrix.getValues(mMatrixValues);
            // mMinZoom = (BrowsePictureActivity.screenWidth / 2f) / imageWidth;
            mMinZoom = 0;
            return mMatrixValues[whichValue];
        }
    
        // Get the scale factor out of the matrix.
        protected float getScale(Matrix matrix) {
            return getValue(matrix, Matrix.MSCALE_X);
        }
    
        protected float getScale() {
            return getScale(mSuppMatrix);
        }
    
        // Combine the base matrix and the supp matrix to make the final matrix.
        protected Matrix getImageViewMatrix() {
            // The final matrix is computed as the concatentation of the base matrix
            // and the supplementary matrix.
            mDisplayMatrix.set(mBaseMatrix);
            mDisplayMatrix.postConcat(mSuppMatrix);
            return mDisplayMatrix;
        }
    
        static final float SCALE_RATE = 1.25F;
    
        // Sets the maximum zoom, which is a scale relative to the base matrix. It
        // is calculated to show the image at 400% zoom regardless of screen or
        // image orientation. If in the future we decode the full 3 megapixel image,
        // rather than the current 1024x768, this should be changed down to 200%.
        protected float maxZoom() {
            if (image == null) {
                return 1F;
            }
    
            float fw = (float) image.getWidth() / (float) mThisWidth;
            float fh = (float) image.getHeight() / (float) mThisHeight;
            float max = Math.max(fw, fh) * 4;
            return max;
        }
    
        protected void zoomTo(float scale, float centerX, float centerY) {
            zoomTo(scale, centerX, centerY, true);
        }
    
        protected void zoomTo(float scale, float centerX, float centerY,
                boolean limit) {
            if (limit) {
                if (scale > mMaxZoom) {
                    scale = mMaxZoom;
                } else if (scale < mMinZoom) {
                    scale = mMinZoom;
                }
            }
    
            float oldScale = getScale();
            float deltaScale = scale / oldScale;
    
            mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY);
            setImageMatrix(getImageViewMatrix());
            center(true, true);
        }
    
        protected void zoomTo(final float scale, final float centerX,
                final float centerY, final float durationMs) {
            final float incrementPerMs = (scale - getScale()) / durationMs;
            final float oldScale = getScale() + mMinZoom;
            final long startTime = System.currentTimeMillis();
    
            mHandler.post(new Runnable() {
                public void run() {
                    long now = System.currentTimeMillis();
                    float currentMs = Math.min(durationMs, now - startTime);
                    float target = oldScale + (incrementPerMs * currentMs);
                    zoomTo(target, centerX, centerY);
                    if (currentMs < durationMs) {
                        mHandler.post(this);
                    }
                }
            });
        }
    
        protected void zoomBigToSmall(final float scale, final float centerX,
                final float centerY, final float durationMs) {
            final float incrementPerMs = (scale - getScale()) / durationMs;
            final float oldScale = getScale() + mMaxZoom;
            final long startTime = System.currentTimeMillis();
    
            mHandler.post(new Runnable() {
                public void run() {
                    long now = System.currentTimeMillis();
                    float currentMs = Math.min(durationMs, now - startTime);
                    float target = oldScale + (incrementPerMs * currentMs);
                    zoomTo(target, centerX, centerY);
                    if (currentMs < durationMs) {
                        mHandler.post(this);
                    }
                }
            });
        }
    
        protected void zoomTo(float scale) {
            float cx = getWidth() / 2F;
            float cy = getHeight() / 2F;
    
            zoomTo(scale, cx, cy);
        }
    
        protected void zoomToPoint(float scale, float pointX, float pointY) {
            float cx = getWidth() / 2F;
            float cy = getHeight() / 2F;
    
            panBy(cx - pointX, cy - pointY);
            zoomTo(scale, cx, cy);
        }
    
        protected void zoomIn() {
            zoomIn(SCALE_RATE);
        }
    
        protected void zoomOut() {
            zoomOut(SCALE_RATE);
        }
    
        protected void zoomIn(float rate) {
            if (getScale() >= mMaxZoom) {
                return; // Don't let the user zoom into the molecular level.
            } else if (getScale() <= mMinZoom) {
                return;
            }
            if (image == null) {
                return;
            }
    
            float cx = getWidth() / 2F;
            float cy = getHeight() / 2F;
    
            mSuppMatrix.postScale(rate, rate, cx, cy);
            setImageMatrix(getImageViewMatrix());
        }
    
        protected void zoomOut(float rate) {
            if (image == null) {
                return;
            }
    
            float cx = getWidth() / 2F;
            float cy = getHeight() / 2F;
    
            // Zoom out to at most 1x.
            Matrix tmp = new Matrix(mSuppMatrix);
            tmp.postScale(1F / rate, 1F / rate, cx, cy);
    
            if (getScale(tmp) < 1F) {
                mSuppMatrix.setScale(1F, 1F, cx, cy);
            } else {
                mSuppMatrix.postScale(1F / rate, 1F / rate, cx, cy);
            }
            setImageMatrix(getImageViewMatrix());
            center(true, true);
        }
    
        public void postTranslate(float dx, float dy) {
            mSuppMatrix.postTranslate(dx, dy);
            setImageMatrix(getImageViewMatrix());
        }
    
        private float mdy = 0.0f;
    
        protected void postTransVerticalDuration(final float dy,
                final float durationMs) {
            final float incrementPerMs = dy / durationMs;
            final long startTime = System.currentTimeMillis();
            mdy = 0.0f;
            mHandler.post(new Runnable() {
                public void run() {
                    long now = System.currentTimeMillis();
                    float currentMs = Math.min(durationMs, now - startTime);
    
                    postTranslate(0, incrementPerMs * currentMs - mdy);
                    mdy = incrementPerMs * currentMs;
    
                    if (currentMs < durationMs) {
                        mHandler.post(this);
                    }
                }
            });
        }
    
        private float mdx = 0.0f;
    
        protected void postTransHorizontalDuration(final float dx,
                final float durationMs) {
            final float incrementPerMs = dx / durationMs;
            final long startTime = System.currentTimeMillis();
            mdx = 0.0f;
            mHandler.post(new Runnable() {
                public void run() {
                    long now = System.currentTimeMillis();
                    float currentMs = Math.min(durationMs, now - startTime);
    
                    postTranslate(incrementPerMs * currentMs - mdx, 0);
                    mdx = incrementPerMs * currentMs;
    
                    if (currentMs < durationMs) {
                        mHandler.post(this);
                    }
                }
            });
        }
    
        protected void panBy(float dx, float dy) {
            postTranslate(dx, dy);
            setImageMatrix(getImageViewMatrix());
        }
    
        private float mDeltaX, mDeltaY;
    
        private float sx, sy;
        private float width, height;
        private float values[] = new float[9];
        private float baseValue;
        private float originalScale;
    
        private final int NONE = 0;
        private final int DRAG = 1;
        private final int ZOOM = 2;
        private int mMod = 0;
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (mDetector != null) {
                mDetector.onTouchEvent(event);
            }
            final ZoomImageView imageView = this;
            final int sWidth = WIDTH;
            final int sHeight = HEIGHT;
            width = imageView.getScale() * imageView.getImageWidth();
            height = imageView.getScale() * imageView.getImageHeight();
    
            Matrix matrix = imageView.getImageMatrix();
            matrix.getValues(values);
            float x = event.getX();
            float y = event.getY();
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                
                mMod = DRAG;
    
                baseValue = 0;
                originalScale = imageView.getScale();
    
                mDeltaX = 0;
                mDeltaY = 0;
                sx = x;
                sy = y;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                
                mMod = ZOOM;
                break;
            case MotionEvent.ACTION_MOVE:
                
                if (event.getPointerCount() == 2) {
                    mMod = ZOOM;
                }
                float deltaX = sx - x;
                float deltaY = sy - y;
                sx = x;
                sy = y;
                if (deltaX != 0.0f) {
                    mDeltaX = deltaX;
                }
    
                if (deltaY != 0.0f) {
                    mDeltaY = deltaY;
                }
    
                switch (mMod) {
                case DRAG:
                    final float left = values[Matrix.MTRANS_X];
                    final float right = left + width;
                    
                    if(right < sWidth && Math.abs(right - sWidth) >= 0.0001f && right < width) { 
                        v.getParent().requestDisallowInterceptTouchEvent(false);
                    } 
                    else if(right > width) {
                        v.getParent().requestDisallowInterceptTouchEvent(false);
                    } 
                    else {
                        v.getParent().requestDisallowInterceptTouchEvent(true);
                    }
                    
                    
                    if (width < sWidth) {
                        deltaX = 0.0f;
                        mDeltaX = deltaX;
                    }
    
                    if (height < sHeight) {
                        deltaY = 0.0f;
                        mDeltaY = deltaY;
                    }
                    
                    
                    imageView.postTranslate(-deltaX, -deltaY);
                    break;
                case ZOOM:
                    if (event.getPointerCount() < 2) {
                        return true;
                    }
    
                    float dx = event.getX(0) - event.getX(1);
                    float dy = event.getY(0) - event.getY(1);
                    float value = FloatMath.sqrt(dx * dx + dy * dy);
                    if (baseValue == 0) {
                        baseValue = value;
                    } else {
                        float scale = value / baseValue;
                        // scale the image
                        imageView.zoomTo(originalScale * scale,
                                (event.getX(0) + event.getX(1)) / 2,
                                (event.getY(0) + event.getY(1)) / 2, false);
                    }
                    break;
                default:
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                        
                final float left = values[Matrix.MTRANS_X];
                final float right = left + width;
                final float top = values[Matrix.MTRANS_Y];
                final float bottom = top + height;
                
                switch (mMod) {
                case DRAG:
                    final float startX = mDeltaX;
                    final float startY = mDeltaY;
                    if (startX != 0) { 
                        if (right < sWidth) {
    //                        ((ViewPager) v.getParent()).requestDisallowInterceptTouchEvent(false);
                            postTransHorizontalDuration(sWidth - right, 200.0f);
                        }
    
                        if (left >= 0) {
                            postTransHorizontalDuration(-left, 200.0f);
                        }
                    }
    
                    if (startY != 0) {
                        if (bottom < sHeight) {
                            postTransVerticalDuration(sHeight - bottom, 200.0f);
                        }
    
                        if (top > 0) {
                            postTransVerticalDuration(-top, 200.0f);
                        }
                    }
    
                    break;
                case ZOOM:
                    final float sr = getScaleRate();
                    final float scale = getScale();
                    mDoubleClick = false;
                    if (sr > scale) {
                        imageView.zoomTo(sr, sWidth / 2, sHeight / 2, 200.0f);
                        return true;
                    } else if (mMaxZoom < scale) {
                        imageView.zoomBigToSmall(sr, sWidth / 2, sHeight / 2,
                                300.0f);
                        return true;
                    }
                    break;
                }
    
                mMod = NONE;
                break;
            default:
            }
    
            return true;
        }
    
        private boolean mDoubleClick;
        private GestureDetector mDetector;
        private OnSimpleListener listener;
    
        public void doubleClick() {
            float scale = getScale();
            if (!mDoubleClick) { 
                zoomTo(1.0f);
                mDoubleClick = true;
            } else if (scale == 1.0f) {
                zoomTo(2.0f);
            } else if (scale == 2.0f) {
                zoomTo(4.0f);
            } else if (scale == 4.0f) {
                zoomTo(1.0f);
            }
        }
    
        @Override
        public boolean onDown(MotionEvent e) {
            // TODO Auto-generated method stub
            return false;
        }
    
        @Override
        public void onShowPress(MotionEvent e) {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            // TODO Auto-generated method stub
            if(listener != null) {
                listener.setOnSimpleClickListenr();
            }
            return true;
        }
    
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                float distanceY) {
            // TODO Auto-generated method stub
            return false;
        }
    
        @Override
        public void onLongPress(MotionEvent e) {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            // TODO Auto-generated method stub
            return false;
        }
    
        public interface OnSimpleListener {
            void setOnSimpleClickListenr();
        }
        
        public void setOnSimpleClickListenr(OnSimpleListener listener) {
            this.listener = listener;
        }
        
    }

    为了不和ViewPager的滑动冲突 主要是在action_move里面加了一个判断:

                    final float left = values[Matrix.MTRANS_X];
                    final float right = left + width;
                    
                    if(right < sWidth && Math.abs(right - sWidth) >= 0.0001f && right < width) { 
                        v.getParent().requestDisallowInterceptTouchEvent(false);
                    } 
                    else if(right > width) {
                        v.getParent().requestDisallowInterceptTouchEvent(false);
                    } 
                    else {
                        v.getParent().requestDisallowInterceptTouchEvent(true);
                    }

    需要源码的M我~~~

  • 相关阅读:
    mvc原理和mvc模式的优缺点
    Paxos算法详细图解
    环境搭建
    elasticsearch 安装
    redis rdb文件解析
    eclipse 远程调试
    java 解析xml
    理想化 redis
    redis 内存
    工作圈redis 使用
  • 原文地址:https://www.cnblogs.com/gongcb/p/3522000.html
Copyright © 2011-2022 走看看