在開發過程中會經常遇到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
三.Activity與View事件傳遞總結

image