实例分析View与ViewGroup的触摸事件传递机制
今天通过一个demo来分析一下,主要是自定义一个Button和layout,通过点击按钮来测试事件的传递效果。
1.首先建立一个类RTButton继承Button;重写它的dispatchTouchEvent,onTouchEvent方法。分别在DOWN,MOVE,UP时打印句子,方便运行时查看。如下代码:
public class RtButton extends Button{
public RtButton(Context context) {
super(context);
}
public RtButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RtButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/** 分发事件
* @param
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RtButton---dispatchTouchEvent----DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RtButton---dispatchTouchEvent----MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RtButton---dispatchTouchEvent----UP");
break;
default:
break;
}
// 获取了MotionEvent各个事件状态
return super.dispatchTouchEvent(event);
}
/** 处理事件
* @param
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RtButton----onTouchEvent----DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RtButton----onTouchEvent----MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RtButton----onTouchEvent----UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
}
2.首先建立一个类RtLayout继承LinearLayout;重写它的dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent方法。分别在DOWN,MOVE,UP时打印句子,方便运行时查看。如下代码:
public class RtLayout extends LinearLayout {
public RtLayout(Context context) {
super(context);
}
public RtLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public RtLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/** 分发事件
* @param
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RTLayout---dispatchTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RTLayout---dispatchTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RTLayout---dispatchTouchEvent---UP");
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
/** 处理事件
* @param
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RtLayout---onInterceptTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RtLayout---onInterceptTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RtLayout---onInterceptTouchEvent---UP");
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("RtLayout---onTouchEvent---DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("RtLayout---onTouchEvent---MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("RtLayout---onTouchEvent---UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
}
3.在布局文件中放入自定义控件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.qzs.event.RtLayout
android:layout_width="match_parent"
android:background="@color/colorAccent"
android:gravity="center"
android:layout_height="match_parent">
<com.qzs.event.RtButton
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="自定义Button"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</com.qzs.event.RtLayout>
</android.support.constraint.ConstraintLayout>
4.在MainActivity中添加按钮的点击事件,再添加按钮的触摸事件,并重写Activity的dispatchTouchEvent,onTouchEvent事件
public class MainActivity extends AppCompatActivity {
private RtButton btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn=findViewById(R.id.btn);
btn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("onTouch----DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("onTouch----MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("onTouch----UP");
break;
default:
break;
}
return false;
}
});
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
System.out.println("<-onClick->");
}
});
}
// Activity的dispatchTouchEvent的事件
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("Activity----dispatchTouchEvent----DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("Activity----dispatchTouchEvent----MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("Activity----dispatchTouchEvent----UP");
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
// 对Activity的ontouchevent的方法事件
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("Activity----ontouchevent----DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("Activity----ontouchevent----MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("Activity----ontouchevent----UP");
break;
default:
break;
}
return super.onTouchEvent(event);
}
}
5.测试
都是默认的状态,我们直接运行一下,结果如下:

从运行结果我们会运行顺序如下:
Activity----dispatchTouchEvent----DOWN
RTLayout---dispatchTouchEvent---DOWN
RtLayout---onInterceptTouchEvent---DOWN
RtButton---dispatchTouchEvent----DOWN
onTouch----DOWN
RtButton----onTouchEvent----DOWN
Activity----dispatchTouchEvent----UP
RTLayout---dispatchTouchEvent---UP
RtLayout---onInterceptTouchEvent---UP
RtButton---dispatchTouchEvent----UP
onTouch----UP
RtButton----onTouchEvent----UP
<-onClick->
由此我们印证了触摸事件是由外到内传递的。
大家是不是对onTouch----DOWN
比较疑惑,ontouch事件为什么早于onTouchEvent事件?其实我们上一节的View源码分析就已经讲到了,截图如下:

从源码中我们发现onTouch早于onTouchEvent
现在我们把RtLayout中的dispatchTouchEvent直接消费掉,也就是返回true
运行后:

说明了事件只传递到了RtLayout。大家也可以自己去试一试,这样才能深入的了解。大家如果有不懂的可以问我。
网友评论