編輯:關於Android編程
我覺得android中的事件分發機制的懵懂期應該是Listview中對於item的點擊和長按事件,那個時候知道item的長按事件是返回boolean值的方法,我們知道要把那個false改成true。。。這樣我們長按事件結束後就不會再繼續觸發點擊事件了
一、引言
1、關於listview中的item點擊事件以及item長按事件的引入(本來是想跟onClick事件一起的,然後就發現一個問題了):Don’t call setOnClickListener for an AdapterView. You probably want setOnItemClickListener instead,就是說android設計中不允許給類似listview的控件(AdapterView)直接寫onClick事件。
//listview中的item點擊事件 lvProduct.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView adapterView, View view, int i, long l) { Log.e(Tag,"onItemClick"); } }); //listview中的item長按事件 lvProduct.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView adapterView, View view, int i, long l) { Log.e(Tag,"onItemLongClick"); return false; } });
我們通過log打印下,在onItemLongClick分別返回false以及true的情況下:
1).返回false的情況下長按item
2).返回true的情況下長按item
我們會發現我們執行長按操作的時候應該是先點擊了這個item然後不動持續一段時間。其實這跟我們的事件消費很相似,如果在長按事件下返回了true,那麼表示這個事件被消費了,然後就不會在繼續傳遞這個動作了。但是如果返回了false,表示這個事件動作還會繼續傳遞,因為你長按item的時候也是點擊了這個item,所以會執行onItemClick事件。
2、再比如,我們再一個Textview上寫onClick事件以及onTouch事件做個試驗:
//點擊事件 textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.w(Tag,"onClick"); } }); //觸摸事件 textView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { Log.w(Tag,"onTouch"); return false; } });
我們通過log打印下在onTouch事件中返回true和false的兩種情況:
1)返回false
正常點擊
正常點擊加移動
2)返回true
正常點擊:
正常點擊加移動
同理我們會發現textview中的現象與我們之前驗證的基本吻合,如果返回true表示事件被消費,將不再繼續傳遞這個動作,如果返回false表示這個動作將會繼續傳遞。但是為什麼onTouch事件會執行兩次或者多次呢,這是因為執行onTouch事件會進行3種基本的操作ACTION_DOWN(手指按下),ACTION_UP(手指抬起),ACTION_MOVE(手指移動)。所以點擊的時候就執行ACTION_DOWN以及ACTION_UP兩次的操作,但是如果你的手指移動了的話,還會進行多次ACTION_MOVE的操作。
二、正題:關於Touch事件分發機制的探索
1、Touch事件的主角們,無非就是與用戶直接交互的Activity,ViewGroup以及View,Touch事件的參與方法也就是事件分發(dispatchTouchEvent),事件攔截(onInterceptTouchEvent),事件響應(onTouchEvent)。這裡需要說明的是Activity中沒有事件攔截,View中也沒有事件攔截,可以理解成是事件攔截是ViewGroup對於自己的子View的Touch事件進行攔截,其實ViewGrop是繼承View的子類,用來充當View的容器,將其中的View視作自己的孩子,對它的子View進行管理,當然它的孩子也可以是ViewGroup類型。所以可以把ViewGroup看做是一個View的集合。
2、Touch事件分發的實質:
當我們手指點擊某個控件的時候,其實是分發找出ACTION_DOWN這個動作的真正實施者,找到這個動作真正的實施者後,將這次事件交給這個實施者進行消費(返回True),那麼這次的動作算是完成了。
3、手指點擊Button的事件分發流程:
假設我們的手指點擊了一個Activity中的Button,假設這個Button在一個ViewGroup中,而這個那麼用戶可以直接看到的是Activity,場景如下(首先應該了解的是ViewGroup的樹形結構,一個ViewGroup包含若干個View):
那麼我們的手指點擊了可見的某一個View,那麼Touch事件的ACTION_DOWN會進行事件分發(dispatchTouchEvent),調用的順序為:1-2-3-6-7-8–4-5,事件分發過程中遇到ViewGroup的時候,首先會判斷ViewGroup的onInterceptTouchEvent是否攔截,如果不攔截,那麼本次事件繼續分發;dispatchTouchEvent事件的返回值為boolean,如果遍歷分發的過程中返回了true,那麼本次分發結束,找到了消費對象,將執行那個View的onTouchEvent事件。加入我們點擊了6號的View,那麼dispatchTouchEvent執行到6號的時候就會中斷,7-8-4-5都不會執行到。那麼需要注意的是1、2、3、6事件都執行了ACTION_DOWN的操作,而只有6號View執行了本次Touch的完整事件。假設分發過程中所有的dispatchTouchEvent都返回了false,那麼本次的Touch事件就由Activity進行消費了。
三、總結:
1.ViewGrop是繼承View的子類,用來充當View的容器,將其中的View視作自己的孩子,對它的子View進行管理,當然它的孩子也可以是ViewGroup類型。所以可以把ViewGroup看做是一個View的集合。
2.ViewGrop和View組成了一個樹狀結果,根節點為Activity。事件分發dispatchTouchEvent分發按照樹形從左到右遞歸遍歷,事件分發是分發ACTION_DOWN的動作。
3.一個完整的Touch事件由一個Action_Down、若干個Action_Move(可以沒有)、一個Aciton_UP組成
4.當Acitivty接收到Touch事件時,將遍歷子View進行ACTION_Down事件的分發。ViewGroup的遍歷可以看成是遞歸的。分發的目的是為了找到真正要處理本次完整觸摸事件的View,找到這個View後會在dispathTouchEvent事件中返回true結束本次ACTION_Down的分發,這個View會在onTouchEvent處理本次事件消費並返回true。
5.onInterceptTouchEvent攔截事件是ViewGroup所特有的攔截自己的子View的ACTION_DOWN事件的分發,使自己獲取本次分發的消費的權利,中止本次事件分發。
6.當本次事件分發所有子View都不處理(返回false),那麼久會觸發Acitivity的onTouchEvent方法,有Activity做本次事件的消費。
7.默認不復寫事件分發機制的方法的話,所有的返回結果都為false。如果要做本次事件分發的終結點的話,記得要把onTouchEvent的返回結果改為true,結束本次Touch事件的傳遞。
好了,我大概只知道這麼多了~~我覺得完全可以轉載別人的博客,但是我覺得應該把自己理解的融合別人的博客,把自己的想法show出來,哪怕只是抄一遍,也比ctrl+c,ctrl+v來的好。重復造輪子是難逃的宿命了,哎哎~
本文介紹Android平台進行數據存儲的五大方式,分別如下:1 使用SharedPreferences存儲數據2 文件存儲數據 &nbs
今天因為工作需要,把以前編寫的一個GPS測試程序拿出來重新修改了一下。這個程序說起來有些歷史了,是我11年編寫的,那時候學了Android開發沒多久,算是一個實驗性的作品
雖然只是模仿,但我覺得這是學習自定義view的必經之路,所以還是把我所學到的東西拿出來與大家一起分享。先貼出一張progressBar的gif圖,其中有水平的進度條,和圓
本文將要模仿Win8界面的一個設計,一個一個的方塊。方法很簡單。這裡自己把圖片改改就可以成為自己想要的界面了。1、首先來看看自定義的MyImageView:package