自定义图片放大缩小(ImageView)

开发中我们有可能对ImageView控件中的图片进行点击放大和缩小的效果,仅在ImageView中设置比较麻烦,

然后就想到了自己定义一个ImageView控件,通过重写ImageView来实现控件中的图片的点击放大效果:

如下,当用的时候可以直接拿来使用:

/**
 * 对图片进行放大缩小
 * Created by acer-pc on 2018/8/21.
 */

public class DoubleScaleImageView  extends AppCompatImageView implements View.OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener {
    private boolean isFirst = false;
    private float doubleScale;// 双击放大的值
    private Matrix mScaleMatrix;
    private float defaultScale;// 默认的缩放值
    private int mLastPinterCount;// 记录上一次多点触控的数量
    private float mLastX;
    private float mLastY;
    private int mTouchSlop;
    private boolean isCanDrag;
    private boolean isCheckLeft;
    private boolean isCheckTop;
    private GestureDetector mGestureDetector;
    public DoubleScaleImageView(Context context) {
        this(context, null);
    }
    public DoubleScaleImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    @SuppressLint("ClickableViewAccessibility")
    public DoubleScaleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mScaleMatrix = new Matrix();
        setScaleType(ScaleType.MATRIX);
        setOnTouchListener(this);
        // getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                float x = e.getX();
                float y = e.getY();
                if (getScale() < doubleScale) {
                    mScaleMatrix.postScale(doubleScale / getScale(), doubleScale / getScale(), x, y);// 放大
                }
                else {
                    mScaleMatrix.postScale(defaultScale / getScale(), defaultScale / getScale(), x, y);// 缩小
                }
                setImageMatrix(mScaleMatrix);
                return super.onDoubleTap(e);
            }
        });
    }
    @Override
    protected void onAttachedToWindow() {// view附加到窗体上时调用该方法
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }
    @SuppressWarnings("deprecation")
    @Override
    protected void onDetachedFromWindow() {// 将视图从窗体上分离的时候调用该方法。
        super.onDetachedFromWindow();
        getViewTreeObserver().removeGlobalOnLayoutListener(this);
    }
    @Override
    public void onGlobalLayout() {// 在这个方法中获取ImageView加载完成后的图片
        if (!isFirst) {
            // 获取控件的宽度和高度
            int width = getWidth();
            int height = getHeight();
            // 得到我们的图片以及图片的宽度及高度
            Drawable drawable = getDrawable();
            if (drawable == null) { return; }
            int imageWidth = drawable.getIntrinsicWidth();// 图片的宽度
            int imageHeight = drawable.getIntrinsicHeight();// 图片的高度
            float scale = 1.0f;
            // 如果图片宽度大于控件宽度,但是图片高度小于控件 高度,我们要缩小图片
            if (imageWidth > width && imageHeight < height) {
                scale = width * 1.0f / imageWidth;
            }
            // 如果图片宽度小于控件宽度,但是图片高度大于控件 高度,我们要缩小图片
            if (imageWidth < width && imageHeight > height) {
                scale = height * 1.0f / imageHeight;
            }
            // 如果图片的宽度都 大于或小于控件宽度,我们则要对图片进行对应缩放,保证图片占满控件
            if ((imageWidth > width && imageHeight > height) || (imageWidth < width && imageHeight < height)) {
                scale = Math.min(width * 1.0f / imageWidth, height * 1.0f / imageHeight);
            }
            // 初始化对应的缩放值
            defaultScale = scale;
            doubleScale = defaultScale * 2;
            // 图片缩放后,将图片要移动到控件中心
            int dx = width / 2 - imageWidth / 2;
            int dy = height / 2 - imageHeight / 2;
            mScaleMatrix.postTranslate(dx, dy);
            mScaleMatrix.postScale(defaultScale, defaultScale, width / 2, height / 2);
            setImageMatrix(mScaleMatrix);
            isFirst = true;
        }
    }
    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (mGestureDetector.onTouchEvent(event)) { return true; }
        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 (mLastPinterCount != pointerCount) {
            isCanDrag = false;
            mLastX = x;
            mLastY = y;

        }
        mLastPinterCount = pointerCount;
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                float dx = x - mLastX;
                float dy = y - mLastY;
                isCanDrag = isMove(dx, dy);
                if (isCanDrag) {
                    RectF rectf = getMatrixRectf();
                    if (null != getDrawable()) {
                        isCheckLeft = isCheckTop = true;
                        if (rectf.width() < getWidth()) {// 如果图片宽度小于控件宽度(屏幕宽度)不允许横向移动
                            dx = 0;
                            isCheckLeft = false;
                        }
                        if (rectf.height() < getHeight()) {// 如果图片高度小于控件高度(屏幕高度)不允许纵向移动
                            dy = 0;
                            isCheckTop = false;
                        }
                        mScaleMatrix.postTranslate(dx, dy);
                        checkTranslateWithBorder();
                        setImageMatrix(mScaleMatrix);
                    }
                }
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mLastPinterCount = 0;
                break;
        }
        return true;
    }
    /**
     * 移动图片时进行边界检查
     */
    private void checkTranslateWithBorder() {
        RectF rectf = getMatrixRectf();
        float delX = 0;
        float delY = 0;
        int width = getWidth();
        int height = getHeight();
        if (rectf.top > 0 && isCheckTop) {
            delY = -rectf.top;
        }
        if (rectf.bottom < height && isCheckTop) {
            delY = height - rectf.bottom;
        }
        if (rectf.left > 0 && isCheckLeft) {
            delX = -rectf.left;
        }
        if (rectf.right < width && isCheckLeft) {
            delX = width - rectf.right;
        }
        mScaleMatrix.postTranslate(delX, delY);
    }
    // 判断是否有移动
    private boolean isMove(float x, float y) {
        return Math.sqrt(x * x + y * y) > mTouchSlop;
    }
    /**
     * 获取图片的位置
     */
    private RectF getMatrixRectf() {
        Matrix matrix = mScaleMatrix;
        RectF recft = new RectF();
        if (getDrawable() != null) {
            recft.set(0, 0, getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight());
            matrix.mapRect(recft);
        }
        return recft;
    }

    // 获取当前图片的缩放值
    private float getScale() {
        float values[] = new float[9];
        mScaleMatrix.getValues(values);
        return values[Matrix.MSCALE_X];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值