Android自定义View实现跟随手指移动

2022-08-17 18:06:22

对View的移动,实现的方法有好几种,原理是通过改变View的位置来移动View,下面来实现这样的效果

    动画的方法

    通过改变View的tranlationX和tranlationY的值来实现移动,首先来写一个自定义View类,重写onTouchEvent方法,实现构造方法

    public class MyView extends View {
        public MyView(Context context) {
            super(context);
        }
    
        public MyView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            return true;//这里我们要消费这个事件,所以返回了true
        }
    }

    关于移动的处理逻辑都在onTouchEvent方法中,下面的代码主要针对onTouchEvent方法修改,其它代码不再贴上了

    首先要获取手指点击移动在屏幕上的坐标,使用

    int x = (int)event.getRawX();//获取x轴上的位置 
    int y = (int)event.getRawY();//获取y轴上的位置

    处理事件的模板代码

    switch(event.getAction()){
        case MotionEvent.ACTION_DOWN://点击事件
            break;
        case MotionEvent.ACTION_MOVE://移动事件
            break;
        case MotionEvent.ACTION_UP://离开事件
            break;
        default:
            break;
    }

    通过判断事件的类型,将在ACTION_MOVE事件中计算移动前后的差值来设置View的translationX和translationY值来改变View的位置,这里需要记录上次的位置,所以需要2个变量,代码如下

    private int mLaxtX;
    private int mLaxtY;
    
      @Override
        public boolean onTouchEvent(MotionEvent event) {
            int x = (int) event.getRawX();
            int y = (int) event.getRawY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_MOVE:
                    int deltaX = x - mLastX;//计算x坐标上的差值
                    int deltaY = y - mLastY;//计算y坐标上的差值
                    float tranX = getTranslationX() + deltaX ;//要平移的x值
                    float tranY = getTranslationY() + deltaY;//要平移的y值
                    setTranslationX(tranX);//设置值
                    setTranslationY(tranY);
                    break;
                case MotionEvent.ACTION_UP:
    
                    break;
                default:
                    break;
            }
            mLastX = x;//记录上次的坐标
            mLastY = y;
            return true;
        }
      layout方法

      View在绘制的时候,会调用onLayout方法来设置显示的位置,可以通过这个方法来实现移动

      //layout方法实现
      switch (event.getAction()) {
         case MotionEvent.ACTION_DOWN:
                      break;
                  case MotionEvent.ACTION_MOVE:
                      //计算偏移量
                      int offsetX = x - mLastX;
                      int offsetY = y - mLastY;
                      //重新布局
                      layout(getLeft() + offsetX, getTop() + offsetY,
                              getRight() + offsetX, getBottom() + offsetY);
                      //也可以使用下面这种方法
      //                offsetLeftAndRight(offsetX);
      //                offsetTopAndBottom(offsetY);
                      break;
                  case MotionEvent.ACTION_UP:
                      break;
                  default:
                      break;
              }
              mLastX = x;
              mLastY = y;
        LayoutParams

        LayoutParams保存了一个View的布局参数,通过改变这个参数,重绘View也可以实现移动

        //LayoutParams方法
         switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int offsetX = x - mLastX;
                        int offsetY = y - mLastY;
                        //示例代码的父View是LinearLayout
                        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
                        layoutParams.leftMargin = getLeft() + offsetX;
                        layoutParams.topMargin = getTop() + offsetY;
                        //下面这两句都可以使用,setLayoutParams也会调用requestLayout
                        //                setLayoutParams(layoutParams);
                        requestLayout();
                        break;
                    case MotionEvent.ACTION_UP:
                        break;
                    default:
                        break;
                }

        这里先介绍这几种方法

        完整代码如下:

        public class MyView extends View {
            public MyView(Context context) {
                super(context);
            }
        
            public MyView(Context context, @Nullable AttributeSet attrs) {
                super(context, attrs);
            }
        
            public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
                super(context, attrs, defStyleAttr);
            }
        
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
                super(context, attrs, defStyleAttr, defStyleRes);
            }
        
            private int mLastX;
            private int mLastY;
        
            @Override
            public boolean onTouchEvent(MotionEvent event) {
                int x = (int) event.getRawX();
                int y = (int) event.getRawY();
                //动画实现移动代码
                //--------------------------------------------------
        //        switch (event.getAction()) {
        //            case MotionEvent.ACTION_DOWN:
        //
        //                break;
        //            case MotionEvent.ACTION_MOVE:
        //                int delaltax = x - mLastX;
        //                int delaltaY = y - mLastY;
        //                float tranX = getTranslationX() + delaltax;
        //                float tranY = getTranslationY() + delaltaY;
        //                setTranslationX(tranX);
        //                setTranslationY(tranY);
        //                break;
        //            case MotionEvent.ACTION_UP:
        //
        //                break;
        //            default:
        //                break;
        //        }
                //-----------------------------------------------
        
                //layout方法实现
        //        switch (event.getAction()) {
        //            case MotionEvent.ACTION_DOWN:
        //                break;
        //            case MotionEvent.ACTION_MOVE:
        //                //计算偏移量
        //                int offsetX = x - mLastX;
        //                int offsetY = y - mLastY;
        //                //重新布局
        //                layout(getLeft() + offsetX, getTop() + offsetY,
        //                        getRight() + offsetX, getBottom() + offsetY);
        //                //也可以使用下面这种方法
                        offsetLeftAndRight(offsetX);
                        offsetTopAndBottom(offsetY);
        //                break;
        //            case MotionEvent.ACTION_UP:
        //                break;
        //            default:
        //                break;
        //        }
                //---------------------------------------------
        
                //LayoutParams方法
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int offsetX = x - mLastX;
                        int offsetY = y - mLastY;
                        //示例代码的父View是LinearLayout
                        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
                        layoutParams.leftMargin = getLeft() + offsetX;
                        layoutParams.topMargin = getTop() + offsetY;
                        //下面这两句都可以使用,setLayoutParams也会调用requestLayout
                        //                setLayoutParams(layoutParams);
                        requestLayout();
                        break;
                    case MotionEvent.ACTION_UP:
                        break;
                    default:
                        break;
                }
        
                mLastX = x;
                mLastY = y;
                return true;
            }
        }

        以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持易采站长站。