Android自定义控件ImageViwe(四)——多点触控实现图片的自由移动



效果图:




功能 :

可以随手指进行自由移动图片


按照适当的比例设置图片的显示

首先将图片按照适当的比例显示在自定义控件中(当图片的宽度或者高度大于控件的宽度或者高度的时候,会对图片进行适当的缩放,当图片的宽高小于控件的宽高的时候,可以进行适当比例的放大,当然后也可以设置是否要进行放大图片的操作,当图片的宽高小于控件的宽高的时候,设置图片显示在控件的中间位置)具体操作过程请点击下面第一条链接进行查看


适当比例设置显示图片:点击查看设置图片显示

设置可随手指自由缩放的图片:点击查看可自由缩放的ImageVeiw

设置双击放大或缩小的图片:点击查看可双击放大或缩小的ImageView


编写图片自由移动的过程分析


首先定义变量

  

   /**
     *记录上一次多点触控的数量
     */
    private int mLastPointerCount;

    /**
     * 记录用户最后一次进行多点触控时的位置
     */
    private float mLastX;
    private float mLastY;


在onTouch方法中进行移动逻辑的操作

首先是获取当前的触控点的个数并计算出触摸中心点的位置

当 当前的触控点的个数发生变化时,记录当前触摸的中心点的位置

//用于存储多点触控的中心点
        float x = 0;
        float y = 0;
        //获取多点触控的数量
        final 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){
            mLastX = x;
            mLastY = y;
        }
        //记录多点触控的数量
        mLastPointerCount = pointerCount;

然后定义方法 获取当前的图片的宽度与高度,并在onTouch方法 中调用获取到保存信息的ReceF


private RectF getMatrixRectF() {
        Matrix matrix = mMatrix;
        final RectF rectF = new RectF();
        final Drawable drawable = getDrawable();
        if (drawable != null) {
            rectF.set(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
            matrix.mapRect(rectF);
        }
        return rectF;
    }

在onTouch方法中进行调用

 final RectF matrixRectF1 = getMatrixRectF();

这里的matrixRectF1就是保存了图片位置及大小信息的对象,这里获取的目的是为了对移动图片的过程中进行一些限制,比如,当图片的宽度高度小于控件的宽与高,就不能进行移动,或者是说当图片的宽高小于控件的宽高,进行自由移动,当手指抬起的进修,将图片自动设置显示在控件中央等等,这完全看个人的需求,如果涉及到这样类似的限制,那么就需要matrixRectF1这个包含图片所有信息的对象来调用了


处理手指的按下移动抬起事件并设置图片随着手指的移动而移动(onTouch方法中)

 switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
              
                break;
            case MotionEvent.ACTION_MOVE:
               
                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
               
                break;

            default:
                break;
        }

处理ACTION_DOWN中的操作,在这里,我们可以进行一步操作,就是判断一个当前的图片,如果当前的图片的宽度或者高度大于控件的宽度与高度,那么我们可以设置
图片随手指的移动处理逻辑主要是在ACTION_MOVE事件中

case MotionEvent.ACTION_MOVE:
            
                //计算偏移量
                float dx = x - mLastX;
                float dy = y - mLastY;
                //判断当前是否在移动
                if (!mIsCanDrag){
                    mIsCanDrag = isMovesAction(dx, dy);
                }
                if (mIsCanDrag) {
                    //如果可以进行移动
                    isCheckLeftAndRight = isCheckTopAndBottom = true;
                    //拿到缩放后的图片的宽高
                    final RectF matrixRectF = getMatrixRectF();
                    if (getDrawable()!=null){
//                        //如果图片宽度小于控件宽度,不可以进行横向移动
//                        if (matrixRectF.width()<getWidth()){
//                            isCheckLeftAndRight = false;
//                            dx =0;
//                        }
//                        //如果图片高度小于控件的高度,不可以进行纵向移动
//                        if (matrixRectF.height()<getHeight()){
//                            isCheckTopAndBottom = false;
//                            dy =0;
//                        }
                        mMatrix.postTranslate(dx, dy);
                        setImageMatrix(mMatrix);
                    }
                }
                //移动过程中时刻记录更新移动的坐标
                mLastX = x;
                mLastY = y;
                break;

可以看的到,在这里,我们有一个方法是判断当前是否可进行移动

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

这里使用到一个mTouchSlop变量,我们需要在构造方法中进行初始化操作

private int mTouchSlop;

   mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件

最后,我们需要在ACTION_UP事件中更新mLastPointerCount


case MotionEvent.ACTION_CANCEL:
                mLastPointerCount = 0;


到这里,我们就实现了图片可以随手指进行多指触控实现自由移动了;



处理多指触控自由移动图片与ViewPager的滑动冲突问题

在这里,我们可以进行判定,当图片的宽度高度大于当前的宽度与高度的时候,可以自由移动图片,ViewPager不可以左右滑动,当图片的宽高小于控件的宽高的时候,不允许移动图片,可以滑动viewPager

我们可以在ACTION_MOVE: ACTION_DOWN方法中判断并处理相关事件


 case MotionEvent.ACTION_DOWN:
             
                    //当前的图片是放大的状态的时候,屏蔽父控件的鎆触摸事件
                    if (matrixRectF1.width()>getWidth()+0.01||matrixRectF1.height()>getHeight()+0.01){
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }
                }
                break;

 case MotionEvent.ACTION_MOVE:
               
                    if (matrixRectF1.width()>getWidth()+0.01||matrixRectF1.height()>getHeight()+0.01){
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }
                

处理当图片的宽高小于控件的宽高时候,手指抬起时候将图片移动到控件中心显示

在这里,可以在ACTION_UP事件触发时候进行处理

case MotionEvent.ACTION_CANCEL:
                
                //当我们的图片的宽度与高度小于控件的宽度与高度的时候,最后手指抬起的时候我们将其移动到控件中心
                final RectF matrixRectF = getMatrixRectF();
                float deltaX=1.0f;
                float deltaY=1.0f;
                if (matrixRectF.width() < getWidth()||matrixRectF.height() < getHeight()) {
                    if (matrixRectF.width() < getWidth()) {
                        deltaX = getWidth() / 2 - matrixRectF.right + matrixRectF.width() / 2;
                    }
                    if (matrixRectF.height() < getHeight()) {
                        deltaY = getHeight() / 2 - matrixRectF.bottom + matrixRectF.height() / 2;
                    }
                    mMatrix.postTranslate(deltaX, deltaY);
                    setImageMatrix(mMatrix);
                }
                break

具体的移动操作距离,可参考上一博文的分析 点击查看移动距离计算分析


效果图:





处理当图片的宽高小于控件的宽高时候,手指抬起时候将图片缓慢移动到控件中心显示




本篇脑筋急转弯解析: 稀饭,  因为物以稀为贵



早起的年轻人 CSDN认证博客专家 移动开发 项目管理 Java
只要用心去做,每一件事情还是有可能成功的,当然成功是没有界限的,只不过是达到自己心里的那个目标,公众号:我的大前端生涯,一个爱喝茶的程序员,通常会搞搞SpringBoot 、Herbinate、Mybatiys、Android、iOS、Flutter、Vue、小程序等.
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页