在开发过程中会经常遇到View与ViewGroup嵌套的问题,如ViewPager嵌套Fragment,而Fragment中又需要实现一个广告滑动,此时广告滑动就会与ViewPager的滑动事件产生冲突,而深入理解Android触摸事件的传递机制则是解决问题的关键。
一.触摸事件的类型(主要有三种)
1.MotionEvent.ACTION_DOWN:手指按下屏幕触发。
2.MotionEvent.ACTION_MOVE:手指在屏幕上移动触发。
3.MotionEvent.ACTION_UP:手指抬起时触发。
二.事件传递的三个阶段
1.方法介绍:
1).分发(DisPatch):对应的方法为:public boolean dispatchTouchEvent(MotionEvent ev),该方法的返回值决定了是否将事件向子视图传递:true:不传递;false:不传递;super.dispatchTouchEvent(ev):传递。
2).拦截(InterCept):对应的方法为:public boolean onInterceptTouchEvent(MotionEvent ev),该方法只有ViewGroup和其子类才有,该方法的返回值决定了是否拦截事件:true:拦截;false:不拦截;super.onInterceptTouchEvent(ev):不拦截。
3).消费(Consume):对应的方法为:public boolean onTouchEvent(MotionEvent event),该方法的返回值决定了是否处理该事件:true:处理;false:不处理;super.onTouchEvent(event):将会调用onClick()方法。
2.Activity与View事件传递演示
1).View代码(继承TextView重写onTouchEvent和dispatchTouchEvent方法)
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.e("MyTextView","onTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("MyTextView","onTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("MyTextView","onTouchEvent:ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.e("MyTextView","dispatchTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("MyTextView","dispatchTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("MyTextView","dispatchTouchEvent:ACTION_UP");
break;
}
return super.dispatchTouchEvent(event);
}
}
2).Activity代码(重写dispatchTouchEvent和onTouchEvent并为MyTextView设置触摸事件)
public class MainActivity extends AppCompatActivity implements View.OnClickListener,View.OnTouchListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyTextView myTextView=findViewById(R.id.tv);
myTextView.setOnClickListener(this);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.e("MainActivity","onTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("MainActivity","onTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("MainActivity","onTouchEvent:ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
Log.e("MainActivity","dispatchTouchEvent:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("MainActivity","dispatchTouchEvent:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("MainActivity","dispatchTouchEvent:ACTION_UP");
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public void onClick(View v) {
Log.e("MyTextView","onClick");
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.e("MainActivity","onTouch:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("MainActivity","onTouch:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("MainActivity","onTouch:ACTION_UP");
break;
}
return false;
}
}
3).设置不同返回值时的结果
◇保持默认值
07-23 13:55:25.707 16976-16976/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_DOWN
07-23 13:55:25.717 16976-16976/com.itfitness.viewandviewgroup E/MyTextView: dispatchTouchEvent:ACTION_DOWN
onTouchEvent:ACTION_DOWN
07-23 13:55:25.797 16976-16976/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_UP
07-23 13:55:25.797 16976-16976/com.itfitness.viewandviewgroup E/MyTextView: dispatchTouchEvent:ACTION_UP
onTouchEvent:ACTION_UP
07-23 13:55:25.807 16976-16976/com.itfitness.viewandviewgroup E/MyTextView: onClick
◇改变Activity的dispatchTouchEvent方法返回值
true:(事件没有分发下去)
07-23 13:56:53.557 17565-17565/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_DOWN
07-23 13:56:53.657 17565-17565/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_UP
false:(事件同样没有分发下去)
07-23 13:58:16.377 18010-18010/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_DOWN
07-23 13:58:16.457 18010-18010/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_UP
◇改变MyTextView的dispatchTouchEvent方法返回值
true:(事件在MyTextView的dispatchTouchEvent方法被阻断)
07-23 13:59:39.087 18470-18470/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_DOWN
07-23 13:59:39.087 18470-18470/com.itfitness.viewandviewgroup E/MyTextView: dispatchTouchEvent:ACTION_DOWN
07-23 13:59:39.177 18470-18470/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_UP
07-23 13:59:39.187 18470-18470/com.itfitness.viewandviewgroup E/MyTextView: dispatchTouchEvent:ACTION_UP
false:(ACTION_DOWN事件在MyTextView的dispatchTouchEvent方法被阻断,并且MainActivity中执行了onTouchEvent方法)
07-23 14:03:03.517 19115-19115/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_DOWN
07-23 14:03:03.517 19115-19115/com.itfitness.viewandviewgroup E/MyTextView: dispatchTouchEvent:ACTION_DOWN
07-23 14:03:03.517 19115-19115/com.itfitness.viewandviewgroup E/MainActivity: onTouchEvent:ACTION_DOWN
07-23 14:03:03.597 19115-19115/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_UP
onTouchEvent:ACTION_UP
◇改变MyTextView的onTouchEvent返回值
true:(ACTION_DOWN事件传递到MyTextView并没有执行onClick方法)
07-23 14:07:47.317 20046-20046/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_DOWN
07-23 14:07:47.317 20046-20046/com.itfitness.viewandviewgroup E/MyTextView: dispatchTouchEvent:ACTION_DOWN
onTouchEvent:ACTION_DOWN
07-23 14:07:47.387 20046-20046/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_UP
07-23 14:07:47.387 20046-20046/com.itfitness.viewandviewgroup E/MyTextView: dispatchTouchEvent:ACTION_UP
onTouchEvent:ACTION_UP
false:(MyTextView没有消费事件反给了MainActivity并且没有执行onClick方法)
07-23 14:11:44.027 20717-20717/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_DOWN
onTouchEvent:ACTION_DOWN
07-23 14:11:44.067 20717-20717/com.itfitness.viewandviewgroup E/MainActivity: dispatchTouchEvent:ACTION_UP
onTouchEvent:ACTION_UP