欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android 自定义View之MotionEvent方法详解

程序员文章站 2022-06-17 10:42:21
...

1.事件类型

这里就引入关于 MotionEvent 的一个重要概念,事件类型。事件类型就是指对象所代表的动作。比如说,当你的一个手指在屏幕上滑动一下时,系统会产生一系列的触摸事件对象,他们所代表的动作有所不同。有的事件代表你手指按下这个动作,有的事件代表你手指在屏幕上滑动,还有的事件代表你手指离开屏幕。常用的如下几种:


ACTION_DOWN:手指按下

ACTION_MOVE:手指一动

ACTION_UP:手指抬起

ACTION_CANCEL:事件取消(极少用到)



2.事件序列

正常情况下,手指触摸屏幕的行为,会触发一系列点击事件,常见的如下几种:

点击屏幕后离开松开,事件序列为 DOWN → UP

点击屏幕滑动一会再松开,事件序列为 DOWN → MOVE → ... → MOVE → UP



3.MotionEvent getX() getY() Demo


3.1.布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
    android:id="@+id/activity_motionevent_textview"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:clickable="true"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:background="#FF0000"
    android:textColor="#FFFFFF"
    android:text="Android 自定义View之MotionEvent方法详解"/>

</RelativeLayout>


3.2.Java代码

public class MotionEventActivity extends AppCompatActivity {

    private TextView textView;
    private int lastX;
    private int lastY;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_motionevent);
        textView= (TextView) findViewById(R.id.activity_motionevent_textview);
        textView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                int action=motionEvent.getAction();
                int x= (int) motionEvent.getX();
                int y= (int) motionEvent.getY();
                switch(action){
                    case MotionEvent.ACTION_DOWN://按下
                        lastX=x;
                        lastY=y;
                        Log.d("TAG", "按下坐标----:("+lastX+","+lastY+")");
                        break;
                    case MotionEvent.ACTION_MOVE://移动
                        float offsetX=x-lastX;
                        float offsetY=y-lastY;
                        Log.d("TAG", "移动X轴位移量offsetX----:"+offsetX);
                        Log.d("TAG", "移动X轴位移量offsetY----:"+offsetY);
                        break;
                    case MotionEvent.ACTION_UP://抬起
                        Log.d("TAG", "抬起坐标----:("+x+","+y+")");
                        break;
                }
                return false;
            }
        });
    }

}


3.3.图解


Android 自定义View之MotionEvent方法详解




3.4.效果

Android 自定义View之MotionEvent方法详解


通过MotionEvent对象我们可以得到点击事件发生的x和y坐标。

系统为我们提供了getX() / getY()和getRawX() / getRawY()。


getX() getY()返回的是相对于相对当前View的左上角的x和y坐标


getRawX() getRawY()返回的是相对于手机屏幕左上角的x和y坐标



4.MotionEvent getRawX() getRawY() Demo


4.1.布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
    android:id="@+id/activity_motionevent_textview"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:clickable="true"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:background="#FF0000"
    android:textColor="#FFFFFF"
    android:text="Android 自定义View之MotionEvent方法详解"/>

</RelativeLayout>


4.2.Java代码

public class MotionEventActivity extends AppCompatActivity {

    private TextView textView;
    private int lastX;
    private int lastY;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_motionevent);
        textView= (TextView) findViewById(R.id.activity_motionevent_textview);
        textView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                int action=motionEvent.getAction();
                int x= (int) motionEvent.getRawX();
                int y= (int) motionEvent.getRawY();
                switch(action){
                    case MotionEvent.ACTION_DOWN://按下
                        lastX=x;
                        lastY=y;
                        Log.d("TAG", "按下坐标----:("+lastX+","+lastY+")");
                        break;
                    case MotionEvent.ACTION_MOVE://移动
                        float offsetX=x-lastX;
                        float offsetY=y-lastY;
                        Log.d("TAG", "移动X轴位移量offsetX----:"+offsetX);
                        Log.d("TAG", "移动X轴位移量offsetY----:"+offsetY);
                        break;
                    case MotionEvent.ACTION_UP://抬起
                        Log.d("TAG", "抬起坐标----:("+x+","+y+")");
                        break;
                }
                return false;
            }
        });
    }

}

4.3.效果

Android 自定义View之MotionEvent方法详解



5.滑动的最小距离TouchSlop

TouchSlop是系统所能识别出的被认为是滑动的最小距离。这是一个常量,就是说,当你手指在屏幕滑动大于这个常量,系统才会认定你滑动屏幕了,它和设备有关,不同的设备这个值可能是不同的。

我们可以通过如下代码获取这个常量:ViewConfiguration.get(this).getScaledTouchSlop();

代码:

float TouchSlop= ViewConfiguration.get(MotionEventActivity.this).getScaledTouchSlop();
Log.d("TAG", "TouchSlop----:"+TouchSlop);

效果:

Android 自定义View之MotionEvent方法详解

即当前设备下滑动的最小距离是24



6.总结

关于OnTouchEvent(MotionEvent事件)事件的层级传递。我们都知道如果给一个控件注册了touch事件,每次点击它的时候都会触发一系列的ACTION_DOWN,ACTION_MOVE,ACTION_UP等事件。这里需要注意,如果你在执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了。简单的说,就是当dispatchTouchEvent在进行事件分发的时候,只有前一个action返回true,才会触发后一个action。