imageSwitcher 实现图片切换

import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageSwitcher;
import android.widget.ImageView;
import android.widget.ViewSwitcher;
import androidx.appcompat.app.AppCompatActivity;

public class ZoomableImageSwitcherActivity extends AppCompatActivity {
    private ImageSwitcher imageSwitcher;
    private GestureDetector gestureDetector;
    private ScaleGestureDetector scaleGestureDetector;
    private int[] imageResources = {R.drawable.image1, R.drawable.image2, R.drawable.image3};
    private int currentIndex = 0;

    private Matrix matrix = new Matrix();
    private PointF lastPoint = new PointF();
    private float scale = 1f;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_zoomable_image_switcher);

        imageSwitcher = findViewById(R.id.imageSwitcher);
        imageSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
            @Override
            public ImageView makeView() {
                return new ImageView(ZoomableImageSwitcherActivity.this);
            }
        });

        // 初始化手势识别器
        gestureDetector = new GestureDetector(this, new GestureListener());
        scaleGestureDetector = new ScaleGestureDetector(this, new ScaleGestureListener());

        // 设置手势监听器
        imageSwitcher.setOnTouchListener((v, event) -> {
            gestureDetector.onTouchEvent(event);
            scaleGestureDetector.onTouchEvent(event);
            return true;
        });

        // 初始显示第一张图片
        setImage(currentIndex);
    }

    private void setImage(int index) {
        imageSwitcher.setImageResource(imageResources[index]);
    }

    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onDown(MotionEvent e) {
            lastPoint.set(e.getX(), e.getY());
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            float dx = e2.getX() - lastPoint.x;
            float dy = e2.getY() - lastPoint.y;
            matrix.postTranslate(-dx, -dy);
            ((ImageView) imageSwitcher.getCurrentView()).setImageMatrix(matrix);
            lastPoint.set(e2.getX(), e2.getY());
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if (Math.abs(velocityX) > Math.abs(velocityY)) {
                // 判断左右滑动
                if (velocityX > 0 && currentIndex > 0) {
                    // 向右滑动,显示前一张图片
                    currentIndex--;
                    setImage(currentIndex);
                    return true;
                } else if (velocityX < 0 && currentIndex < imageResources.length - 1) {
                    // 向左滑动,显示后一张图片
                    currentIndex++;
                    setImage(currentIndex);
                    return true;
                }
            }
            return false;
        }
    }

    private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float scaleFactor = detector.getScaleFactor();
            scale *= scaleFactor;
            scale = Math.max(0.1f, Math.min(scale, 10.0f)); // 控制缩放范围在0.1到10倍之间
            matrix.setScale(scale, scale, detector.getFocusX(), detector.getFocusY());
            ((ImageView) imageSwitcher.getCurrentView()).setImageMatrix(matrix);
            return true;
        }
    }
}

一、内部拦截法

getParent().requestDisallowInterceptTouchEvent(true) 请求父容器不拦截

此时父容器应该在Action_down不拦截处理

public boolean onInterceptTouchEvent(MotionEvent ev) {

        if (event.getAction = MotionEvent.ACTION_DOWN) {

               super.onInterceptTouchEvent(ev)

                return false;

        }

        retrun true;

}

二、外部拦截法

photoView

package com.example.myapplication.image;

import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.OverScroller;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;

public class PhotoView extends AppCompatImageView {
    private Bitmap bitmap;
    private Paint paint;

    // 偏移值
    private float originalOffsetX;
    private float originalOffsetY;

    // 一边全屏,一边留白
    private float smallScale;
    // 一边全屏,一边超出屏幕
    private float bigScale;

    private float OVER_SCALE_FACTOR = 1.5f;

    private float currentScale;

    private boolean isEnlarge;

    private GestureDetector gestureDetector;

    private float offsetX;
    private float offsetY;

    private OverScroller overScroller;

    private FlingRunner flingRunner;

    private ScaleGestureDetector scaleGestureDetector;

    private boolean isScale;

    private int mLastX;
    private int mLastY;

    public PhotoView(Context context) {
        this(context, null);
    }

    public PhotoView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PhotoView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        // 获取bitmap对象
        paint = new Paint();

        gestureDetector = new GestureDetector(context, new PhotoGestureListener());

        overScroller = new OverScroller(context);

        flingRunner = new FlingRunner();

        scaleGestureDetector = new ScaleGestureDetector(context, new PhotoScaleGestureListener());
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();


        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastX;
                int deltaY = y - mLastY;
                // 这个条件由业务逻辑决定,看什么时候 子View将事件让出去
                if (Math.abs(deltaX) > Math.abs(deltaY)) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                break;

            }
            default:
                break;
        }

        mLastX = x;
        mLastY = y;
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 双指操作优先
        boolean result = scaleGestureDetector.onTouchEvent(event);
        if (!scaleGestureDetector.isInProgress()) {
            result = gestureDetector.onTouchEvent(event);
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Drawable drawable = getDrawable();
        if (drawable != null) {
            initBitmap(drawable);
        }


        float scaleFraction = (currentScale - smallScale) / (bigScale - smallScale);
        canvas.translate(offsetX * scaleFraction, offsetY * scaleFraction);

        // smallScale --》 bigScale
        canvas.scale(currentScale, currentScale, getWidth() / 2f, getHeight() / 2f);

        // 绘制bitmap
        canvas.drawBitmap(bitmap, originalOffsetX, originalOffsetY, paint);
    }

    private void initBitmap(@NonNull Drawable drawable ) {
        if (drawable instanceof BitmapDrawable) {
            Bitmap bitmap1 = ((BitmapDrawable) drawable).getBitmap();
            if (bitmap1 == null || bitmap1.equals(bitmap)) {
                return;
            }
            bitmap = bitmap1;
            Log.d("testhyy", bitmap1.toString());
            // 需要得到 浮点数,否则会留条小缝
            originalOffsetX = (getWidth() - bitmap.getWidth()) / 2f;
            originalOffsetY = (getHeight() - bitmap.getHeight()) / 2f;

            // 图片是横向的
            if ((float) bitmap.getWidth() / bitmap.getHeight() > (float) getWidth() / getHeight()) {
                smallScale = (float) getWidth() / bitmap.getWidth();
                bigScale = (float) getHeight() / bitmap.getHeight() * OVER_SCALE_FACTOR;
            } else { // 纵向的图片
                smallScale = (float) getHeight() / bitmap.getHeight();
                bigScale = (float) getWidth() / bitmap.getWidth() * OVER_SCALE_FACTOR;
            }
            currentScale = smallScale;
        }
    }

    // onMeasure --> onSizeChanged
    // 每次改变尺寸时也会调用
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    public void setImageResource(int resId) {
        bitmap = BitmapFactory.decodeResource(getResources(), resId);
        super.setImageResource(resId);
    }

    class PhotoGestureListener extends GestureDetector.SimpleOnGestureListener {
        // Up时触发  双击的时候,触发两次??第二次抬起时触发
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return super.onSingleTapUp(e);
        }

        // 长按 -- 300ms
        @Override
        public void onLongPress(MotionEvent e) {
            super.onLongPress(e);
        }

        /**
         * 类似move事件
         *
         * @param e1
         * @param e2
         * @param distanceX 在 X 轴上滑过的距离(单位时间) 旧位置 - 新位置
         * @param distanceY
         * @return
         */
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            // 只有在放大的情况下,才能进行移动
            if (isEnlarge) {
                offsetX -= distanceX;
                offsetY -= distanceY;
                fixOffsets();
                invalidate();
            }
            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        // 抛掷
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if (isEnlarge) {
                // 只会处理一次
                overScroller.fling((int) offsetX, (int) offsetY, (int) velocityX, (int) velocityY,
                        -(int) (bitmap.getWidth() * bigScale - getWidth()) / 2,
                        (int) (bitmap.getWidth() * bigScale - getWidth()) / 2,
                        -(int) (bitmap.getHeight() * bigScale - getHeight()) / 2,
                        (int) (bitmap.getHeight() * bigScale - getHeight()) / 2, 600, 600);
                postOnAnimation(flingRunner);
            }

            return super.onFling(e1, e2, velocityX, velocityY);
        }

        // 延时触发 100ms -- 点击效果,水波纹
        @Override
        public void onShowPress(MotionEvent e) {
            super.onShowPress(e);
        }

        // 按下 -- 注意:直接返回true
        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        // 双击 -- 第二次点击按下的时候 -- 40ms(小于表示:防抖动) -- 300ms
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            isEnlarge = !isEnlarge;
            if (isEnlarge) {
                offsetX = (e.getX() - getWidth() / 2f) - (e.getX() - getWidth() / 2) * bigScale / smallScale;
                offsetY = (e.getY() - getHeight() / 2f) - (e.getY() - getHeight() / 2) * bigScale / smallScale;
                fixOffsets();
                // 启动属性动画
                getScaleAnimator().start();
            } else {
                getScaleAnimator().reverse();
            }
//            invalidate();
            return super.onDoubleTap(e);
        }

        // 双击第二次 down、move、up都会触发
        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            return super.onDoubleTapEvent(e);
        }

        // 单击按下时触发,双击时不触发,
        // 延时300ms触发TAP事件
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            return super.onSingleTapConfirmed(e);
        }
    }

    class FlingRunner implements Runnable {

        @Override
        public void run() {
            // 动画还在执行 则返回true
            if (overScroller.computeScrollOffset()) {
                offsetX = overScroller.getCurrX();
                offsetY = overScroller.getCurrY();
                invalidate();
                // 没帧动画执行一次,性能更好
                postOnAnimation(this);
            }
        }
    }

    private void fixOffsets() {
        offsetX = Math.min(offsetX, (bitmap.getWidth() * bigScale - getWidth()) / 2);
        offsetX = Math.max(offsetX, -(bitmap.getWidth() * bigScale - getWidth()) / 2);
        offsetY = Math.min(offsetY, (bitmap.getHeight() * bigScale - getHeight()) / 2);
        offsetY = Math.max(offsetY, -(bitmap.getHeight() * bigScale - getHeight()) / 2);
    }

    /**
     * 属性动画,设置放大缩小的效果
     */
    private ObjectAnimator scaleAnimator;

    private ObjectAnimator getScaleAnimator() {
        if (scaleAnimator == null) {
            scaleAnimator = ObjectAnimator.ofFloat(this, "currentScale", 0);
        }
        if (isScale) {
            isScale = false;
            scaleAnimator.setFloatValues(smallScale, currentScale);
        } else {
//             放大缩小的范围
            scaleAnimator.setFloatValues(smallScale, bigScale);
        }
        return scaleAnimator;
    }

    // 属性动画,值会不断地从 smallScale 慢慢 加到 bigScale, 通过反射调用改方法
    public void setCurrentScale(float currentScale) {
        this.currentScale = currentScale;
        invalidate();
    }

    class PhotoScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {

        float initialScale;

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            if ((currentScale > smallScale && !isEnlarge)
                    || (currentScale == smallScale && isEnlarge)) {
                isEnlarge = !isEnlarge;
            }
            currentScale = initialScale * detector.getScaleFactor();
            isScale = true;
            invalidate();
            return false;
        }

        // 注意:返回true,消费事件
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            initialScale = currentScale;
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {

        }
    }


}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值