自定义view四:手势缩放和可移动的ImageView

public class ZoomImageView extends AppCompatImageView implements OnScaleGestureListener,    OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener {private static final String TAG       = ZoomImageView.class.getSimpleName();public static final  float  SCALE_MAX = 15.0f;private static final float  SCALE_MID = 5.0f;/** * 初始化时的缩放比例,如果图片宽或高大于屏幕,此值将小于0 */private float   initScale = 4.0f;private boolean once      = true;/** * 用于存放矩阵的9个值 */private final float[] matrixValues = new float[9];/** * 缩放的手势检测 */private       ScaleGestureDetector mScaleGestureDetector = null;private final Matrix               mScaleMatrix          = new Matrix();/** * 用于双击检测 */private GestureDetector mGestureDetector;private boolean         isAutoScale;private int mTouchSlop;private float mLastX;private float mLastY;private boolean isCanDrag;private int     lastPointerCount;private boolean isCheckTopAndBottom = true;private boolean isCheckLeftAndRight = true;private float             scale;private SingleTapListener singleTapListener;public ZoomImageView(Context context) {    this(context, null);}public ZoomImageView(Context context, AttributeSet attrs) {    super(context, attrs);    super.setScaleType(ScaleType.MATRIX);    mGestureDetector = new GestureDetector(context,            new SimpleOnGestureListener() {                @Override                public boolean onDoubleTap(MotionEvent e) {                    if (isAutoScale)                        return true;                    float x = e.getX();                    float y = e.getY();                    Log.e("DoubleTap", getScale() + " , " + initScale);                    if (getScale() < SCALE_MID) {                        ZoomImageView.this.postDelayed(                                new AutoScaleRunnable(SCALE_MID, x, y), 16);                        isAutoScale = true;                    } else if (getScale() >= SCALE_MID                            && getScale() < SCALE_MAX) {                        ZoomImageView.this.postDelayed(                                new AutoScaleRunnable(SCALE_MAX, x, y), 16);                        isAutoScale = true;                    } else {                        ZoomImageView.this.postDelayed(                                new AutoScaleRunnable(initScale, x, y), 16);                        isAutoScale = true;                    }                    return true;                }                @Override                public boolean onSingleTapConfirmed(MotionEvent e) {                    if (singleTapListener != null) {                        singleTapListener.doSingle();                    }                    return super.onSingleTapConfirmed(e);                }            });    mScaleGestureDetector = new ScaleGestureDetector(context, this);    this.setOnTouchListener(this);}/** * 自动缩放的任务 * * @author zhy */private class AutoScaleRunnable implements Runnable {    static final float BIGGER  = 1.07f;    static final float SMALLER = 0.93f;    private float mTargetScale;    private float tmpScale;    /**     * 缩放的中心     */    private float x;    private float y;    /**     * 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小     *     * @param targetScale     */    public AutoScaleRunnable(float targetScale, float x, float y) {        this.mTargetScale = targetScale;        this.x = x;        this.y = y;        if (getScale() < mTargetScale) {            tmpScale = BIGGER;        } else {            tmpScale = SMALLER;        }    }    @Override    public void run() {        // 进行缩放        mScaleMatrix.postScale(tmpScale, tmpScale, x, y);        checkBorderAndCenterWhenScale();        setImageMatrix(mScaleMatrix);        final float currentScale = getScale();        // 如果值在合法范围内,继续缩放        if (((tmpScale > 1f) && (currentScale < mTargetScale))                || ((tmpScale < 1f) && (mTargetScale < currentScale))) {            ZoomImageView.this.postDelayed(this, 16);        } else        // 设置为目标的缩放比例        {            final float deltaScale = mTargetScale / currentScale;            mScaleMatrix.postScale(deltaScale, deltaScale, x, y);            checkBorderAndCenterWhenScale();            setImageMatrix(mScaleMatrix);            isAutoScale = false;        }    }}@SuppressLint("NewApi")@Overridepublic boolean onScale(ScaleGestureDetector detector) {    float scale       = getScale();    float scaleFactor = detector.getScaleFactor();    if (getDrawable() == null)        return true;    /**     * 缩放的范围控制     */    if ((scale < SCALE_MAX && scaleFactor > 1.0f)            || (scale > initScale && scaleFactor < 1.0f)) {        /**         * 最大值最小值判断         */        if (scaleFactor * scale < initScale) {            scaleFactor = initScale / scale;        }        if (scaleFactor * scale > SCALE_MAX) {            scaleFactor = SCALE_MAX / scale;        }        /**         * 设置缩放比例         */        mScaleMatrix.postScale(scaleFactor, scaleFactor,                detector.getFocusX(), detector.getFocusY());        checkBorderAndCenterWhenScale();        setImageMatrix(mScaleMatrix);    }    return true;}/** * 在缩放时,进行图片显示范围的控制 */private void checkBorderAndCenterWhenScale() {    RectF rect   = getMatrixRectF();    float deltaX = 0;    float deltaY = 0;    int width  = getWidth();    int height = getHeight();    // 如果宽或高大于屏幕,则控制范围    if (rect.width() >= width) {        if (rect.left > 0) {            deltaX = -rect.left;        }        if (rect.right < width) {            deltaX = width - rect.right;        }    }    if (rect.height() >= height) {        if (rect.top > 0) {            deltaY = -rect.top;        }        if (rect.bottom < height) {            deltaY = height - rect.bottom;        }    }    // 如果宽或高小于屏幕,则让其居中    if (rect.width() < width) {        deltaX = width * 0.5f - rect.right + 0.5f * rect.width();    }    if (rect.height() < height) {        deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();    }    Log.e(TAG, "deltaX = " + deltaX + " , deltaY = " + deltaY);    mScaleMatrix.postTranslate(deltaX, deltaY);}/** * 根据当前图片的Matrix获得图片的范围 * * @return */private RectF getMatrixRectF() {    Matrix   matrix = mScaleMatrix;    RectF    rect   = new RectF();    Drawable d      = getDrawable();    if (null != d) {        rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());        matrix.mapRect(rect);    }    return rect;}@Overridepublic boolean onScaleBegin(ScaleGestureDetector detector) {    return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector) {}@Overridepublic boolean onTouch(View v, MotionEvent event) {    if (mGestureDetector.onTouchEvent(event))        return true;    mScaleGestureDetector.onTouchEvent(event);    float x = 0, y = 0;    // 拿到触摸点的个数    final int pointerCount = event.getPointerCount();    // 得到多个触摸点的x与y均值    for (int i = 0; i < pointerCount; i++) {        x += event.getX(i);        y += event.getY(i);    }    x = x / pointerCount;    y = y / pointerCount;    /**     * 每当触摸点发生变化时,重置mLasX , mLastY     */    if (pointerCount != lastPointerCount) {        isCanDrag = false;        mLastX = x;        mLastY = y;    }    lastPointerCount = pointerCount;    RectF rectF = getMatrixRectF();    switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            if (rectF.width() > getWidth() || rectF.height() > getHeight()) {                getParent().requestDisallowInterceptTouchEvent(true);            }            break;        case MotionEvent.ACTION_MOVE:            if (rectF.width() > getWidth() || rectF.height() > getHeight()) {                getParent().requestDisallowInterceptTouchEvent(true);            }            Log.e(TAG, "ACTION_MOVE");            float dx = x - mLastX;            float dy = y - mLastY;            if (!isCanDrag) {                isCanDrag = isCanDrag(dx, dy);            }            if (isCanDrag) {                if (getDrawable() != null) {                    // if (getMatrixRectF().left == 0 && dx > 0)                    // {                    // getParent().requestDisallowInterceptTouchEvent(false);                    // }                    //                    // if (getMatrixRectF().right == getWidth() && dx < 0)                    // {                    // getParent().requestDisallowInterceptTouchEvent(false);                    // }                    isCheckLeftAndRight = isCheckTopAndBottom = true;                    // 如果宽度小于屏幕宽度,则禁止左右移动                    if (rectF.width() < getWidth()) {                        dx = 0;                        isCheckLeftAndRight = false;                    }                    // 如果高度小雨屏幕高度,则禁止上下移动                    if (rectF.height() < getHeight()) {                        dy = 0;                        isCheckTopAndBottom = false;                    }                    mScaleMatrix.postTranslate(dx, dy);                    checkMatrixBounds();                    setImageMatrix(mScaleMatrix);                }            }            mLastX = x;            mLastY = y;            break;        case MotionEvent.ACTION_UP:        case MotionEvent.ACTION_CANCEL:            Log.e(TAG, "ACTION_UP");            lastPointerCount = 0;            break;    }    return true;}/** * 获得当前的缩放比例 * * @return */public final float getScale() {    mScaleMatrix.getValues(matrixValues);    return matrixValues[Matrix.MSCALE_X];}@Overrideprotected void onAttachedToWindow() {    super.onAttachedToWindow();    getViewTreeObserver().addOnGlobalLayoutListener(this);}@SuppressWarnings("deprecation")@Overrideprotected void onDetachedFromWindow() {    super.onDetachedFromWindow();    getViewTreeObserver().removeGlobalOnLayoutListener(this);}public void setScale(float scale) {    this.scale = scale;}@Overridepublic void onGlobalLayout() {    Drawable d = getDrawable();    if (d == null) return;    if (once) {        Log.e(TAG, d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());        int width  = getWidth();        int height = getHeight();        // 拿到图片的宽和高        int dw = d.getIntrinsicWidth();        int dh = d.getIntrinsicHeight();        scale = 1f;        // 如果宽和高都大于屏幕,则让其按按比例适应屏幕大小        if (dw > width && dh > height) {            scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);        } else if (dw > width && dh <= height) {// 如果图片的宽或者高大于屏幕,则缩放至屏幕的宽或者高            scale = width * 1.0f / dw;        } else if (dh > height && dw <= width) {            scale = height * 1.0f / dh;        } else if (dh < height && dw < width) {//图片长宽都小于屏幕,则放大至屏幕的宽或者高            scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);        }        initScale = scale;        Log.e(TAG, "initScale = " + initScale);        mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2);        mScaleMatrix.postScale(scale, scale, getWidth() / 2,                getHeight() / 2);        // 图片移动至屏幕中心        setImageMatrix(mScaleMatrix);        once = false;    }}/** * 移动时,进行边界判断,主要判断宽或高大于屏幕的 */private void checkMatrixBounds() {    RectF rect = getMatrixRectF();    float       deltaX     = 0, deltaY = 0;    final float viewWidth  = getWidth();    final float viewHeight = getHeight();    // 判断移动或缩放后,图片显示是否超出屏幕边界    if (rect.top > 0 && isCheckTopAndBottom) {        deltaY = -rect.top;    }    if (rect.bottom < viewHeight && isCheckTopAndBottom) {        deltaY = viewHeight - rect.bottom;    }    if (rect.left > 0 && isCheckLeftAndRight) {        deltaX = -rect.left;    }    if (rect.right < viewWidth && isCheckLeftAndRight) {        deltaX = viewWidth - rect.right;    }    mScaleMatrix.postTranslate(deltaX, deltaY);}/** * 是否是推动行为 * * @param dx * @param dy * @return */private boolean isCanDrag(float dx, float dy) {    return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;}public interface SingleTapListener {    void doSingle();}public void setOnSingleTapListener(SingleTapListener singleTapListener) {    this.singleTapListener = singleTapListener;}

}

更多相关文章

  1. android 查看图片、保存图片
  2. Android(安卓)TextView显示html图片
  3. Android(安卓)EditText加入图片混编显示
  4. 背景图片颜色渐变
  5. android bitmap(图片)旋转90度
  6. android 显示 网络图片
  7. Android(安卓)GLSurfaceView在屏幕旋转后绘图区域异常的解决办法
  8. Android腾讯微薄客户端开发十四:首页menu菜单
  9. android 图片圆角处理

随机推荐

  1. Android_TextView属性介绍
  2. android私有目录直接读取
  3. 【android】shape使用总结
  4. [Android] 问题记录 - Android 支持的度
  5. 浅谈android的selector,背景选择器 .
  6. 更新ADT遇到问题,requires plug-in "org.e
  7. Android 状态栏通知Notification
  8. android布局的一些知识
  9. android模块&相关技术
  10. 调试Android WebView