android事件分發機制總結

Android事件分發機制 java

 

android 普通view(不包含ViewGroup)和activity中主要有一下兩個方法處理事件: android

public boolean dispatchTouchEvent(MotionEvent ev) // 分發事件
public boolean onTouchEvent(MotionEvent event)     // 處理事件

 

ViewGroup中還一個方法: ide

public boolean onInterceptTouchEvent(MotionEvent ev) // 攔截事件

 

一、activity中,順序是:事件分發->事件處理,若是在事件分發時消費了某個事件(return true)則事件處理將不會接收到該事件。 this

 

public class MainActivity extends Activity {
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 事件分發
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_MOVE) {
 System.out.println("dispatchTouchEvent-->ACTION_MOVE");
return true; // 表示我消費了,不繼續分發
}
return super.dispatchTouchEvent(ev);
}
// 處理事件
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("onTouchEvent-->ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("onTouchEvent-->ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("onTouchEvent-->ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}

 

以上代碼的結果: spa

onTouchEvent-->ACTION_DOWN code

dispatchTouchEvent-->ACTION_MOVE 事件

dispatchTouchEvent-->ACTION_MOVE get

dispatchTouchEvent-->ACTION_MOVE it

dispatchTouchEvent-->ACTION_MOVE io

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

onTouchEvent-->ACTION_UP

 

從結果上看:ACTION_MOVE並無到onTouchEvent中,由於咱們在dispatchTouchEvent判斷,若是是ACTION_MOVEreturn true表示消耗掉該事件,事件就不會分發到onTouchEvent中,全部onTouchEvent只能接收到ACTION_DOWNACTION_UP事件。

 

二、普通view的事件分發

 

一個普通view的事件由dispatchTouchEvent分發事件,事件的順序是ACTION_DOWNACTION_MOVEACTION_UP,若是有一個事件被消費掉,其餘的事件不會執行到;分發事件由onTouch首先接收到,若是onTouch返回true了,表示消費掉了該事件,那麼該viewclick事件將不會執行。

 

mButton.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
  System.out.println("onTouch..."+event.getAction());
return true;  // 消費了該事件,下面的click事件不會執行
}
});
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 由於上面的onTouch把事件消費了,則這裏執行不到
System.out.println("onClick...");
}
});

 

 

三、ViewGroup的事件分發:

ViewGroup的事件分發稍微麻煩點,以自定義的LinearLayout : MyLayout爲例;

事件發生,首先由MyLayout的dispatchTouchEvent進行事件的分發
而後到MyLayout的onInterceptTouchEvent攔截事件
一、onInterceptTouchEvent若是return true表示攔截該事件,並在MyLayout中處理
剩下的事件,事件繼續由MyLayout進行分發,分發機制同上面的view事件分發機制,但此次分發不會考慮分發給子view,也不會走onInterceptTouchEvent,由於系統已經知道
該套事件MyLayout已經攔截,因此直接在MyLayout中處理

二、若是MyLayoutonInterceptTouchEvent返回false(默認返回false[1]),表示不攔截事件,由MyLayout的子view(以Button爲例)的dispatchTouchEvent開始分發事件,分發機制就是上面的view事件分發機制。

public class MyLayout extends LinearLayout {
	public MyLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public MyLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		System.out.println("dispatchTouchEvent");
		return super.dispatchTouchEvent(ev);
	}
	
	
	// 事件發生, 首先由MyLayout的dispatchTouchEvent進行事件的分發
	// 而後到MyLayout的onInterceptTouchEvent攔截事件
	// 若是return true表示攔截該事件,並在MyLayout中處理
	// 剩下的事件繼續由MyLayout進行分發,此次分發不會考慮分發給
	// 子view,也不會走onInterceptTouchEvent,由於系統已經知道
	// 該套事件MyLayout已經攔截,因此直接在MyLayout中處理
	
	// 該demo的執行結果:
	// 第一套down、move、up :
	// dispatchTouchEvent
	// onInterceptTouchEvent
	// action_down...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_up...
	
	// 再一套:
	// dispatchTouchEvent
	// onInterceptTouchEvent
	// action_down...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_move...
	// dispatchTouchEvent
	// action_up...
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		System.out.println("onInterceptTouchEvent");
		if(ev.getAction() == MotionEvent.ACTION_DOWN) {
			return true;
		}
		return super.onInterceptTouchEvent(ev);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("action_down...");
			break;
		case MotionEvent.ACTION_UP:
			System.out.println("action_up...");
			break;
		case MotionEvent.ACTION_MOVE:
			System.out.println("action_move...");
			break;
		}
		return true;
	}
}

執行的結果:

 第一套down、move、up :
dispatchTouchEvent
onInterceptTouchEvent
action_down...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_up...
 
再一套:
dispatchTouchEvent
onInterceptTouchEvent
action_down...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_up...

 

MyLinearLayout

public class MyLinearLayout extends LinearLayout{
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;  
// 這裏返回true, 則攔截掉事件,不會再往子view傳遞,繼續調用該view的dispachTouchEvent和onTouch
}
}

 

 

MainActivity:

public class MainActivity extends Activity {
private MyLinearLayout mLayout;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLayout = (MyLinearLayout) findViewById(R.id.layout);
mButton = (Button) findViewById(R.id.click);
mLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("layout touch " + event.getAction());
return false;
}
});
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 由於在MyLinearLayout中已經攔截了事件,因此這裏不會輸出
               System.out.println("button click...");
}
});
}
}

 

執行結果:

layout touch 0


注意[1] : ListViewonInterceptTouchEvent默認返回的是true,表示攔截了事件。因此在listView中的Button按照普通設置click的方法是不能點擊的。

相關文章
相關標籤/搜索