編輯:關於Android編程
篇外話:先來說下今天的日期,今天是2015年02月18日也就是大年三十,大家都在歡歡喜喜的准備過大年,活動也各式各樣,搓麻將、打撲克、放煙花、准備看春晚,而我卻還在敲代碼,我只想說身為程序員的我們,真的屌絲的不能再屌絲了。雖然很屌絲,但我在這裡還是要給大家拜個年,祝大家羊年喜氣洋洋、寫出來的代碼少 bug、產品少改需求!當然當大家看到這篇 blog 的時候已經過完了年,因為我寫這篇 blog 是在家裡,而我家裡木有網絡,所以還得等到到了工作之地才能放出來,好了,回歸正題。
Android 事件處理機制說難也不難,說簡單也不簡單,為什麼這麼說呢?因為我相信大部分有了一定 Android 基礎的同學,想要分析 Android 事件處理機制,都是可以分析出來了;但要靈活運用它卻又覺得很吃力,而且往往需要查閱各種資料文檔,才能真正把它運用起來。今天我帶領大家對 Android 事件處理機制做一次全方位的分析,從而達到大家對 Android 事件處理有一個更深、更形象的認識!
一、初體驗:
相信大部分的人對 Android 事件處理機制的分析,都是通過打印 log 的方式,這裡也是通過這種方式來分析;首先准備三個類 MainActivity 、EventLayout 、EventTextView ,這幾個類分別是什麼都做了些什麼呢?我們看看代碼就知道。
1、MainActivity
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean handle = false ;
String str = ACTION_DOWN;
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
str = ACTION_DOWN;
break ;
case MotionEvent.ACTION_MOVE:
str = ACTION_MOVE;
handle = true ;
break;
case MotionEvent.ACTION_UP:
str = ACTION_UP;
break;
}
Log.v(zgy,=====Activity=====dispatchTouchEvent========+str) ;
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
String str = ACTION_DOWN;
boolean handle = false ;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
str = ACTION_DOWN;
break ;
case MotionEvent.ACTION_MOVE:
str = ACTION_MOVE;
handle = true ;
break;
case MotionEvent.ACTION_UP:
str = ACTION_UP;
break;
}
Log.v(zgy,=====Activity=====onTouchEvent========+str) ;
return super.onTouchEvent(event);
}
}
2、EventLayout
/**
* Created by gyzhong on 15/2/18.
*/
public class EventLayout extends LinearLayout {
public EventLayout(Context context) {
super(context);
}
public EventLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EventLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
String str = ACTION_DOWN;
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
str = ACTION_DOWN;
break ;
case MotionEvent.ACTION_MOVE:
str = ACTION_MOVE;
break;
case MotionEvent.ACTION_UP:
str = ACTION_UP;
break;
}
Log.v(zgy, =====ViewGroup=====onInterceptTouchEvent========+str) ;
if(handle){
return handle ;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean handle = false ;
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
str = ACTION_DOWN;
break ;
case MotionEvent.ACTION_MOVE:
str = ACTION_MOVE;
break;
case MotionEvent.ACTION_UP:
str = ACTION_UP;
break;
}
Log.v(zgy, =====ViewGroup=====dispatchTouchEvent========+str) ;
if(handle){
return handle ;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
String str = ACTION_DOWN;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
str = ACTION_DOWN;
break ;
case MotionEvent.ACTION_MOVE:
str = ACTION_MOVE;
break;
case MotionEvent.ACTION_UP:
str = ACTION_UP;
break;
}
Log.v(zgy,=====ViewGroup=====onTouchEvent========+str) ;
return super.onTouchEvent(event);
}
}
3、EventTextView
/**
* Created by gyzhong on 15/2/18.
*/
public class EventTextView extends TextView {
public EventTextView(Context context) {
super(context);
}
public EventTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EventTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
String str = ACTION_DOWN;
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
str = ACTION_DOWN;
break ;
case MotionEvent.ACTION_MOVE:
str = ACTION_MOVE;
break;
case MotionEvent.ACTION_UP:
str = ACTION_UP;
break;
}
Log.v(zgy, =====View=====dispatchTouchEvent========+str+ ,getX() =+ev.getX()) ;
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
String str = ACTION_DOWN;
boolean handle = false ;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
str = ACTION_DOWN;
break ;
case MotionEvent.ACTION_MOVE:
str = ACTION_MOVE;
break;
case MotionEvent.ACTION_UP:
str = ACTION_UP;
break;
}
Log.v(zgy,=====View=====onTouchEvent========+str) ;
return super.onTouchEvent(event);
}
}
通過代碼可以看到,3個類基本上什麼都沒做,只是重寫了父類的dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent方法,也只是在其中加入了調試信息,那再來看看 xml
這裡把我們重寫的 自定義的 View 放入布局中。運行代碼,開始調試,然後點擊EventTextView可以看到 log 信息:
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
通過信息和結合我們所學的知識點,還是很容易得出結論來:
Activity 的 dispatchTouchEvent的事件分發給ViewGroup,ViewGroup先通過事件攔截onInterceptTouchEvent(只有 ViewGroup 才有此方法)來判斷,是否攔截,如果沒有攔截則將事件分發給 View 的分發機制dispatchTouchEvent;View 獲取到事件後,就開始調用 onTouchEvent 方法,如果 View 的 onTouchEvent 未把事件消費掉,則把事件有傳遞給 ViewGroup 的 onTouchEvent,同理,ViewGroup 未把事件消費掉,繼續往下級傳到了 Activity 的 onTouchEvent 事件處理中。文字講解終究是有點難理解,需要結合圖文來講解,那麼我們來看下下面這張圖,應該很清晰明了。
vcHLwb249rnYvPy0yqOswLm92LrNz/u30aOsxuTKtba8ysfNvMas1tCx7cq+tcQgcmV0dXJuILe1u9jWtaOs1NogZGlzcGF0Y2hUb3VjaEV2ZW50IM7Sw8fPsLnf08PAub3Yo6y2+NTaIG9uVG91Y2hFdmVudCDW0NTyz7C539PDz/u30cC0y7XD96OouPbIy8+wud+2+NLRo6mho3JldHVybiBmYWxzZSCx7cq+ysK8/s60sbtkaXNwYXRjaFRvdWNoRXZlbnTAub3Yo6zSss60sbtvblRvdWNoRXZlbnTP+7fRoaO6w8HLo6y1vbTLztLDx7XEQW5kcm9pZCDKwrz+tKbA7bv61sa31s72zerBy6OsuNDQu7TzvNK1xNTEtsGho7q5oaK6uaGiurmhoqGioaIg1ea1xLfWzvbN6sHLwvCjrMjnufvWu8rH1eLR+b7NveHK+MHLo6zO0tKysru74dTatPO5/cTqtcSjrNTa1eLA77/gsca/4LHGtcTQtCBibG9noaPEx8O0vdPPwsC0ztLDx734yOu12rb+vde2zqGjPC9wPgo8cD62/qGiye62yMbKzvY8YnIgLz4Ku7m8x7XDx7DD5rXa0ru917bOtcSx6sziJnJkcXVvO7P1zOXR6SZyZHF1bzvOqsqyw7S90LP1zOXR6cTYo7+089bCv8nS1MjPzqrKx87Sw8e1xLXa0rvToc/zo6zO0sPH1+6z9bjQvvWz9sC0tcS2q873oaPO3sLbyse4+b7d19S8urXEwt+8rcC0zcbA7aOsu7nKx7j5vt241bjVztLDx7+0tb21xLX3ytTQxc+iwLS/tKOsysK8/rSmwO27+rXE1sbV+8zlwfezzLa8ysewtNXVyc/D5s28MS0xtcTB97PMwLTX37XEoaO1q8rHo6zPuNDEtcTNrNGnv8+2qL+0tb3By9fuuvPBvdDQtffK1NDFz6I8L3A+CjxwcmUgY2xhc3M9"brush:java;">
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
對,你沒有看錯,我也沒有調錯,ACTION_UP的時候它確實只打印了兩行,並都是在 Activity 中打印的。並不像 ACTION_DOWN 的時候執行了
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
也許這樣看還不明顯,再來看看一下調試信息
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
這裡可以看到只有在 ACTION_DOWN 的時候是按照我們分析的流程圖來執行,而 ACTION_MOVE、ACTION_UP 都只是執行了 Activity 的dispatchTouchEvent和onTouchEvent,這是為什麼?難道我們不是按照上面那張流程圖的流程來執行?這裡我可以肯定的告訴大家,上面那張圖的流程是絕對沒有問題的,只是有些事件被攔截或消費掉。並且這裡告訴大家一個結論:
ViewGroup 和 View的dispatchTouchEvent分發事件在 action 為ACTION_DOWN時沒有被攔截且onTouchEvent的處理事件在 action 為ACTION_DOWN時未被消費,當 action 為ACTION_MOVE或ACTION_UP時,dispatchTouchEvent和onTouchEvent只有在 activity 被調用。想搞清楚和驗證這個結論的同學,可以自己根據源碼深入探究!
通過以上結論,可知,在手指滑動或者抬起的時候,ViewGroup 和 View 的dispatchTouchEvent和onTouchEvent未被執行,因為事件未被攔截或者消費。
我在網上看過一些 Android 事件處理機制的帖子和 bolg,我記得有這樣一個問題,為什麼我在分析 Android 事件處理的時候,用 TextView 和 Button ,分析出來的結果不一樣呢?這裡我們用的是 TextView 分析的,我們也來看看 Button 的效果,到底哪裡不一樣。新建一個 EventButton類和 EventTextView 一樣,除了繼承的對象不同之外。
EventButton
/**
* Created by gyzhong on 15/2/18.
*/
public class EventButton extends Button {
public EventButton(Context context) {
super(context);
}
public EventButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EventButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
String str = ACTION_DOWN;
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
str = ACTION_DOWN;
break ;
case MotionEvent.ACTION_MOVE:
str = ACTION_MOVE;
break;
case MotionEvent.ACTION_UP:
str = ACTION_UP;
break;
}
Log.v(zgy, =====View=====dispatchTouchEvent========+str+ ,getX() =+ev.getX()) ;
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
String str = ACTION_DOWN;
boolean handle = false ;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
str = ACTION_DOWN;
break ;
case MotionEvent.ACTION_MOVE:
str = ACTION_MOVE;
break;
case MotionEvent.ACTION_UP:
str = ACTION_UP;
break;
}
Log.v(zgy,=====View=====onTouchEvent========+str) ;
return super.onTouchEvent(event);
}
}
記得別忘記修改 xml 中的內容
再次運行代碼,果然,結果不一樣
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====onInterceptTouchEvent========ACTION_MOVE
=====View=====dispatchTouchEvent========ACTION_MOVE
=====View=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====onInterceptTouchEvent========ACTION_MOVE
=====View=====dispatchTouchEvent========ACTION_MOVE
=====View=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====onInterceptTouchEvent========ACTION_UP
=====View=====dispatchTouchEvent========ACTION_UP
=====View=====onTouchEvent========ACTION_UP
我們根據調試結果再加上流程圖不難推測出,在 View 的 onTouchEvent 的事件處理機制中把事件消費掉了,並且在 action 為 ACTION_DOWN、ACTION_MOVE、ACTION_UP 的時候全部消費掉了,所以不會再往下執行,那我們就來看看源碼是否如此。
進入到 View 的onTouchEvent方法中
public boolean onTouchEvent(MotionEvent event) {
//省略部分代碼
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
}
//省略很多代碼
return true;
}
return false;
}
以上代碼,我把有用的幾行提取出來了,可以看到,有一個判斷條件,如果 View 是可以點擊的狀態,return true 事件將會被消費掉,否則 return false 不會被消費掉。而我們都知道 TextView 默認狀態是不可點擊的, Button 是可以點擊的,所以這也就是為什麼 TextView 和 Button 的調試效果不一樣,如果把 Button 設為不可點擊,效果就和 TextView 的完全一樣,有興趣的同學可以自己嘗試一下。
四、總結
講了那麼多,其實核心就是那張圖片,只要掌握了那張圖片中事件的流程基本上就沒什麼問題了;
這張圖反應出來的信息有:
1、Android 事件傳遞是層級傳遞的;
2、dispatchTouchEvent從低級向上級傳遞,而onTouchEvent剛好相反;
3、onInterceptTouchEvent返回為 true 時,將執行同級的onTouchEvent,而dispatchTouchEvent和onTouchEvent返回 true 時,將終止事件的傳遞。
還有一點特別重要,也是比較難理解的一點,就是我前面說的那個結論。
ViewGroup 和 View的dispatchTouchEvent分發事件在 action 為ACTION_DOWN時沒有被攔截且onTouchEvent的處理事件在 action 為ACTION_DOWN時未被消費,當 action 為ACTION_MOVE或ACTION_UP時,dispatchTouchEvent和onTouchEvent只有在 activity 被調用。
最後我將在下篇 blog 中,通過自定義通用型的下拉刷新來實戰事件處理機制,如果有興趣的同學,可以關注。
這裡附上一張 時序圖和log 信息
Activity dispatchTouchEvent——->Action == ACTION_DOWN return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
Activity dispatchTouchEvent——->Action == ACTION_MOVE return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
Activity dispatchTouchEvent——->Action == ACTION_UP return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
ViewGroup dispatchTouchEvent——->Action == ACTION_DOWN return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====onTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====onTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====onTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====onTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
ViewGroup dispatchTouchEvent——->Action == ACTION_MOVE return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
ViewGroup dispatchTouchEvent——->Action == ACTION_UP return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
ViewGroup onInterceptTouchEvent——->Action == ACTION_DOWN return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
View dispatchTouchEvent——->Action == ACTION_DOWN return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====onInterceptTouchEvent========ACTION_MOVE
=====View=====dispatchTouchEvent========ACTION_MOVE
=====View=====onTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====onInterceptTouchEvent========ACTION_UP
=====View=====dispatchTouchEvent========ACTION_UP
=====View=====onTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
View dispatchTouchEvent——->Action == ACTION_MOVE return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
View dispatchTouchEvent——->Action == ACTION_UP return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
View onTouchEvent ——->Action == ACTION_DOWN return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====onInterceptTouchEvent========ACTION_MOVE
=====View=====dispatchTouchEvent========ACTION_MOVE
=====View=====onTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====onInterceptTouchEvent========ACTION_UP
=====View=====dispatchTouchEvent========ACTION_UP
=====View=====onTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
View onTouchEvent ——->Action == ACTION_MOVE return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
View onTouchEvent ——->Action == ACTION_UP return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
ViewGroup onTouchEvent ——->Action == ACTION_DOWN return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====dispatchTouchEvent========ACTION_MOVE
=====ViewGroup=====onTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====dispatchTouchEvent========ACTION_UP
=====ViewGroup=====onTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
ViewGroup onTouchEvent ——->Action == ACTION_MOVE return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
ViewGroup onTouchEvent ——->Action == ACTION_UP return true
=====Activity=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====dispatchTouchEvent========ACTION_DOWN
=====ViewGroup=====onInterceptTouchEvent========ACTION_DOWN
=====View=====dispatchTouchEvent========ACTION_DOWN
=====View=====onTouchEvent========ACTION_DOWN
=====ViewGroup=====onTouchEvent========ACTION_DOWN
=====Activity=====onTouchEvent========ACTION_DOWN
=====Activity=====dispatchTouchEvent========ACTION_MOVE
=====Activity=====onTouchEvent========ACTION_MOVE
=====Activity=====dispatchTouchEvent========ACTION_UP
=====Activity=====onTouchEvent========ACTION_UP
最近幾年,很多跨平台游戲框架已經出現。這些框架來填補空白,由於不斷增長的興趣和多樣性的移動游戲平台越來越大。今天是采取比以往任何時候都更容易游戲引擎和開發你的第一個游戲。
最近的一些學習心得:功能實現:點擊圓形頭像之後可以實現相冊上傳或者開啟相機,然後把得到的圖片經過剪裁,把剪裁過的圖片設置為頭像的背景圖步驟:第一步:自定義一個類,繼承Im
Android提供了實現按照秒計時的API,今天就是用這個API實現簡單的倒計時。來個布局: 對應活動中的代碼如下: pa
Fragment相當於一個小型activity,因為Fragment可以實現activity中所有的功能,不同的是Fragment可以嵌入activity,一個activ