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

对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;     } }

推荐阅读