<Android>打造自己的可双击放大、多指缩放、放大等功能的ImageView

不多说上代码

package com.sdp.panda.myviewapp.view;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.widget.ImageView;

/**
 * Created by 80926 on 2016/11/23.
 */


public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,
        ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener {
    //多指的放大与缩小的成员变量
    private boolean mOnce;
    private float mInitScale;//初始化的最小缩放值
    private float mMidScale;//双击的缩放值
    private float mMaxScale;//放大的最大值
    private Matrix mMatrix;
    private ScaleGestureDetector mScaleGestureDetector;//手势

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~````
    //自由移动的成员变量
    private int mLastPointerCount;//最后多指的数目
    private float mLastX;
    private float mLastY;
    private int mTouchSlop;
    private boolean isCanDrag;//可以拖拽
    private boolean isMoveTopAndBottom;//是否可以上移下移
    private boolean isMoveLeftAndRight;

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``~~~~~~~~~~~~~~~~
    //双击的成员变量
    private GestureDetector mGestureDetector;//双击的类
    private boolean isAutoScale;//避免用户一直双击

    public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    public ZoomImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ZoomImageView(Context context) {
        this(context, null);//一个参数的引用两个参数的
    }

    private void init(Context context) {
        mMatrix = new Matrix();
//        setScaleType(ScaleType.MATRIX);
        mScaleGestureDetector = new ScaleGestureDetector(context, this);
        setOnTouchListener(this);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();//是可以move的值
        mGestureDetector = new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                if (isAutoScale){
                    return true;
                }
                float x = e.getX();
                float y = e.getY();
                if (getScale()<mMidScale){
//                    mMatrix.postScale(mMidScale/getScale(),mMidScale/getScale(),x,y);
//                    setImageMatrix(mMatrix);
                    postDelayed(new AutoScaleRunnable(mMidScale,x,y),15);
                    isAutoScale = true;
                }else {
//                    mMatrix.postScale(mInitScale/getScale(),mInitScale/getScale(),x,y);
//                    setImageMatrix(mMatrix);
                    postDelayed(new AutoScaleRunnable(mInitScale,x,y),15);
                    isAutoScale = true;
                }
                return true;
            }
        });
    }


    @Override
    public void onGlobalLayout() {
        if (!mOnce) {

            int width = getWidth();//控件的宽和高
            int height = getHeight();
            Drawable drawable = getDrawable();
            if (drawable == null) {
                return;
            }
            float scaleSize = 0;//缩放尺寸
            int dWidth = drawable.getIntrinsicWidth();//图片的宽和高
            int dHeight = drawable.getIntrinsicHeight();
            if (dWidth > width && dHeight < height) {
                scaleSize = width * 1.0f / dWidth;//防止为0,提前转换为float类型
            }
            if (dHeight > height && dWidth < width) {
                scaleSize = height * 1.0f / dHeight;
            }
            if (dWidth > width && dHeight > height || dWidth < width && dHeight < height) {
                scaleSize = Math.min(height * 1.0f / dHeight, width * 1.0f / dWidth);
            }
            mInitScale = scaleSize;
            mMidScale = mInitScale * 2;//双击的初始化的两倍
            mMaxScale = mInitScale * 4;//最大是初始化的4倍
            //将图片移动至屏幕的中心
            int centerX = (width - dWidth) / 2;
            int centerY = (height - dHeight) / 2;
            mMatrix.postTranslate(centerX, centerY);
            mMatrix.postScale(mInitScale, mInitScale, width / 2, height / 2);
            setImageMatrix(mMatrix);//矩阵 长度为9的一元数组
            mOnce = true;
        }
    }

    @Override
    protected void onAttachedToWindow() {//实现window的时候天剑
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }

    //获取当前图片的缩放值
    private float getScale() {
        float[] values = new float[9];
        mMatrix.getValues(values);
        return values[Matrix.MSCALE_X];
    }

    @Override
    public boolean onScale(ScaleGestureDetector detector) {//缩放中
        float scaleFactor = detector.getScaleFactor();//获取缩放值
        //缩放区间 initScale~maxScale;
        float scale = getScale();
        if (getDrawable() == null) {
            return true;
        }
        if (scale < mMaxScale && scaleFactor > 1.0f ||
                scale > mInitScale && scaleFactor < 1.0f) {
            if (scale * scaleFactor < mInitScale) {
                scaleFactor = mInitScale / scale;
            }
            if (scale * scaleFactor > mMaxScale) {
                scaleFactor = mMaxScale / scale;
            }
            mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
            setImageViewInCenterWhenCheck();
            setImageMatrix(mMatrix);
        }
        return true;
    }

    //获取可以得到图片的四个角的矩形
    private RectF getMatrixRectF() {
        Matrix mMatrix = this.mMatrix;
        RectF rectF = new RectF();
        Drawable d = getDrawable();
        if (d != null) {
            rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            mMatrix.mapRect(rectF);
        }
        return rectF;
    }

    //设置图片在缩放最后中间
    private void setImageViewInCenterWhenCheck() {
        RectF matrixRectF = getMatrixRectF();
        float postX = 0;
        float postY = 0;
        int width = getWidth();
        int height = getHeight();
        if (matrixRectF.width() >= width) {
            if (matrixRectF.left > 0) {
                postX = -matrixRectF.left;
            }
            if (matrixRectF.right < width) {
                postX = width - matrixRectF.right;
            }
        }
        if (matrixRectF.height() >= height) {
            if (matrixRectF.top > 0) {
                postY = -matrixRectF.top;
            }
            if (matrixRectF.bottom < height) {
                postY = height - matrixRectF.bottom;
            }
        }
        //宽度和高度小于控件的宽和高的时候让其居中
        if (matrixRectF.width() < width) {
            postX = width / 2 - matrixRectF.right + matrixRectF.width() / 2;
        }
        if (matrixRectF.height() < height) {
            postY = height / 2 - matrixRectF.bottom + matrixRectF.height() / 2;
        }
        mMatrix.postTranslate(postX, postY);
    }
    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {//开始
        return true;
    }
    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {}

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (mGestureDetector.onTouchEvent(event)){
            return true;
        }
        mScaleGestureDetector.onTouchEvent(event);
        float x = 0;
        float y = 0;
        int pointerCount = event.getPointerCount();
        for (int i = 0; i < pointerCount; i++) {
            x += event.getX(i);
            y += event.getY(i);
        }
        x /= pointerCount;
        y /= pointerCount;
        if (mLastPointerCount != pointerCount) {
            isCanDrag = false;
            mLastX = x;
            mLastY = y;
        }
        mLastPointerCount = pointerCount;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //解决与viewPager的冲突事件:加上0.01防止误差
                if (getMatrixRectF().width()>getWidth()+0.01||getMatrixRectF().height()>getHeight()+0.01){
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (getMatrixRectF().width()>getWidth()+0.01||getMatrixRectF().height()>getHeight()+0.01){
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                float dx = x - mLastX;
                float dy = y - mLastY;//移动量
                if (!isCanDrag) {
                    isCanDrag = isCanTouchMove(dx, dy);
                }
                if (isCanDrag) {
                    RectF matrixRectF = getMatrixRectF();
                    if (getDrawable() != null) {
                        isMoveLeftAndRight = isMoveTopAndBottom = true;
                        if (matrixRectF.width() < getWidth()) {//如果图片的宽和高小于控件的宽和高不允许移动
                            isMoveLeftAndRight = false;
                            dx = 0;
                        }
                        if (matrixRectF.height() < getHeight()) {
                            isMoveTopAndBottom = false;
                            dy = 0;
                        }
                        mMatrix.postTranslate(dx, dy);
                        WhenMoveCheck();
                        setImageMatrix(mMatrix);
                    }
                }
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mLastPointerCount = 0;
                break;
        }
        return true;
    }
    //该方法是用于制约图片移动的时候不会留白
    private void WhenMoveCheck() {
        RectF matrixRectF = getMatrixRectF();
        float dx = 0;
        float dy = 0;
        int width = getWidth();
        int height = getHeight();
        if (matrixRectF.top>0&&isMoveTopAndBottom){
            dy = - matrixRectF.top;
        }
        if (matrixRectF.bottom<height&&isMoveTopAndBottom){
            dy = height-matrixRectF.bottom;
        }
        if (matrixRectF.left>0&&isMoveLeftAndRight){
            dx = -matrixRectF.left;
        }
        if (matrixRectF.right<width&& isMoveLeftAndRight){
            dx = width-matrixRectF.right;
        }
        mMatrix.postTranslate(dx,dy);
        setImageMatrix(mMatrix);
    }

    private boolean isCanTouchMove(float dx, float dy) {
        return Math.sqrt(dx * dx + dy * dy) > mTouchSlop;
    }

    private class AutoScaleRunnable implements Runnable{
        private float mTargetScale;//缩放的目标值
        private float x;
        private float y;//中心点
        private final float BIGGER = 1.05F;
        private final float SMALL = 0.95F;
        private float tmpScale;
        public AutoScaleRunnable(float targetScale,float x,float y){
            this.mTargetScale = targetScale;
            this.x = x;
            this.y = y;
            if (getScale()<mTargetScale){
                tmpScale = BIGGER;
            }
            if (getScale()>mTargetScale){
                tmpScale = SMALL;
            }
        }
        @Override
        public void run() {
            mMatrix.postScale(tmpScale,tmpScale,x,y);
            setImageViewInCenterWhenCheck();
            setImageMatrix(mMatrix);
            float currentScale = getScale();
            if (tmpScale>1.0f&&currentScale <mTargetScale || tmpScale<1.0f && currentScale>mTargetScale){
                postDelayed(this,15);
            }else {//设置目标值
                float scale = mTargetScale/currentScale;
                mMatrix.postScale(scale,scale,x,y);
                setImageViewInCenterWhenCheck();
                setImageMatrix(mMatrix);
                isAutoScale = false;
            }
        }
    }
}

此自定义控件可以与viewPager等使用,但是需处理其冲突事件

因为在viewPager中如不处理就无法进行对放大的图片进行点击移动的效果。。。
上述代码中:
  if (getMatrixRectF().width()>getWidth()+0.01
  ||getMatrixRectF().height()>getHeight()+0.01){
                getParent().requestDisallowInterceptTouchEvent(true);
            }
 正是处理这个冲突事件,只是先处理ImageView的放大缩小事件,最后可以进行滑动
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Android平台上,可以使用一些常用的手势操作来实现图片的平移、双指缩放双击放大缩小。 首先,为了实现平移功能,可以使用触摸事件的ACTION_MOVE来处理手指在屏幕上滑动的操作。通过计算滑动距离,可以改变图片的位置从而实现平移效果。 其次,双指缩放可以使用触摸事件的ACTION_POINTER_DOWN和ACTION_POINTER_UP来追踪并处理触摸屏幕上第二个手指按下和松开的操作。在处理时,可以通过计算两个手指触摸点之间的距离来改变图片的缩放比例,从而实现双指缩放效果。 最后,双击放大缩小可以通过设置一个双击的监听器来实现。在双击监听器的回调方法中,可以根据当前的图片缩放状态来判断是进行放大操作还是缩小操作。并根据需要更改图片的缩放比例,实现双击放大缩小功能。 在实现上述功能时,可以使用Android提供的一些核心类来辅助开发,如View、MotionEvent、GestureDetector等。同时,还可以结合自定义View和动画效果来提升用户体验,使图片的平移、缩放双击动作更加流畅和自然。 总之,通过合理运用触摸事件、手势识别、双击监听器等技术,可以在Android上实现图片的平移、双指缩放双击放大缩小功能,从而提升用户与应用程序的交互体验。 ### 回答2: 在Android开发中,可以通过使用ImageView控件来实现对图片的平移、双指缩放双击放大缩小操作。 1. 平移:可以通过使用Matrix类对ImageView进行变换来实现图片的平移。首先,我们需要为ImageView设置一个OnTouchListener来监听用户的手势操作。在手势操作的回调方法中,可以通过获取手指按下和移动的位置差来计算出需要平移的距离,然后通过设置Matrix的平移矩阵来实现图片的平移效果。 2. 双指缩放:可以通过GestureDetector类来监听双指缩放手势。在手势操作的回调方法中,可以获取到两个手指的起始位置和当前位置,通过计算两个手指之间的距离差来判断缩放的比例。然后,再通过设置Matrix的缩放矩阵来实现图片的缩放效果。需要注意的是,在进行缩放操作时,还需要考虑到手指中心点的位置变化。 3. 双击放大缩小:也可以通过GestureDetector类来监听双击手势。在手势操作的回调方法中,可以判断是否发生了双击事件,并获取到双击的位置。当双击事件发生时,可以通过判断当前图片的缩放比例来决定是放大还是缩小。通过设置Matrix的缩放矩阵和平移矩阵来实现图片的放大缩小效果。 需要注意的是,为了实现图片的平移、双指缩放双击放大缩小操作,我们需要对ImageView进行一系列的监听和处理操作。同时,为了方便管理和控制这些操作,可以将相关的代码封装成一个自定义的图片控件,并在该控件中进行处理。 ### 回答3: Android 提供了多种方法来实现图片的平移、双指缩放双击放大缩小功能。 首先,要实现图片的平移,我们可以使用 GestureDetector 类。可以通过重写 onScroll() 方法来检测用户的滑动手势,然后将图片的位置进行相应的调整,从而实现平移效果。 其次,要实现双指缩放功能,我们可以借助 ScaleGestureDetector 类。通过重写 onScale() 方法,我们可以获取用户的缩放手势,并根据手势的缩放比例调整图片的尺寸,从而实现双指缩放的效果。 最后,要实现双击放大缩小功能,我们可以使用 GestureDetector 类。可以通过重写 onDoubleTap() 方法来检测用户的双击手势,然后根据当前图片的尺寸和双击事件的位置,来判断是进行放大还是缩小操作,最后将图片的尺寸进行相应的调整,实现双击放大缩小的效果。 需要注意的是,以上的功能实现是基于 Android 的原生 API,还有其他第三方库也提供了更便捷的方法来实现这些功能,例如 PhotoView 库,它提供了更多灵活的选项和交互效果,可以更加方便地实现图片的平移、缩放双击操作。 综上所述,Android 针对图片的平移、双指缩放双击放大缩小,可以通过重写相应的手势监听方法或使用第三方库来实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值