閱讀291 返回首頁    go 王者榮耀


ListView事件的研究

 

1. ListView的OnItemClickListener不被觸發的另外一種情況

image

 

如上圖,在一個ItemView中,隻有一個TextView位於最左側,他的右側是空白區域,沒有任何控件,當點擊右側區域時,並不會觸發OnItemClickListener,當點擊TextView所在的區域時,就能觸發這個事件。

看看這個事件的執行流程

image

右側空白的部分沒有View控件,也就是說雖然用手指點擊了這一部分,但是沒有view獲取焦點,Android的事件觸發是從頂層view一層層往下尋找的,如果有view獲取焦點,就交給這個view處理,如果沒有,就交給activity處理。

click事件與touch事件的傳播方式是不同的

給ListView同時添加對touch和itemClick的監聽事件,他們的觸發順序是:

actionDown--------》action up---------》onItemClick

他們的執行流程為:

先按照touch事件的處理流程進行,然後在進行click事件的處理,這就說明,當用戶按下屏幕,產生了兩個事件,一個是touch事件,一個是click事件,添加到主線程的隊列中。

 

用戶手指觸摸屏幕,滾動ListView,看起來也進行了click操作,但是結果是,隻觸發了touch事件,沒有觸發click事件。

 

2. ListView 獲取焦點和ItemView獲取焦點之間的關係

2.1 ListView不獲取焦點,ItemView能獲取焦點嗎?

通過設置ItemView的android:focusable="true"    android:focusableInTouchMode="true"屬性,可以使ItemView在Touch mode 下獲取焦點,默認情況下,Touch mode下ItemView,menu等等控件都是不能獲取焦點的。隻有ListView獲取了焦點之後,ItemView才能獲取焦點。

 

實驗一:

設置ListView的focusable屬性為true,ItemView的android:focusable="true"    android:focusableInTouchMode="true",自定義touch事件監聽器,重寫onTouch方法

public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //clear();
                int x = (int) event.getX();
                int y = (int) event.getY();
                int position = mListView.pointToPosition(x, y);
                int firstVisiblePosition = mListView.getFirstVisiblePosition();
                view = mListView.getChildAt(position-firstVisiblePosition);
                if(view==null) return false;
                if(view.isFocusable()){
                    Log.i(tag, "ItemView is focusable ");
                }
                if(view.isFocusableInTouchMode()){
                    Log.i(tag, "ItemView is focusable in touchMode");
                }
                if(view.isInTouchMode()){
                    Log.i(tag, "device is in touch mode.");
                }
                if(mListView.isFocusable()){
                    Log.i(tag, "mListView is focusable ");
                }
                if(mListView.isFocusableInTouchMode()){
                    Log.i(tag, "mListView isFocusableInTouchMode in touchMode");
                }
                
                if(view.isFocused()){
                    Log.i(tag, "ItemView have get focus ");
                }
                if(mListView.isFocused()){
                    Log.i(tag, "mListView have get focus ");
                }
                if(view.isPressed()){
                    Log.i(tag, "ItemView have get pressed ");
                }
                break;
            case MotionEvent.ACTION_UP:
                if(view==null) return false;
                Log.i(tag, "OnTouchListener: up is working ");
                if(view.isFocused()){
                    Log.i(tag, "ItemView have get focus ");
                }
                break;
            default:
                break;
            }
            return false;
        }

打印結果為:

ItemView is focusable
ItemView is focusable in touchMode
device is in touch mode.
mListView is focusable
mListView isFocusableInTouchMode in touchMode
mListView have get focus
OnTouchListener: up is working

當用戶觸摸屏幕的時候,觸發了touch事件,但是隻有ListView獲取了焦點,itemView卻沒有獲得焦點,說明itemView在默認狀態下,即時設置了能獲取焦點,能在touchmode下獲取焦點,實際上也是不能的

而ListView的focusable屬性即時不設為true,也是能夠獲取焦點的,那麼如何讓ItemView獲取焦點呢,有兩個方法,一個是View類的requestFocus()方法,一個是ListView的requestChildFocus(child, focused)方法,還有就是requestFocusFromTouch()方法,該方法是View類的方法,ListView繼承了該方法。

我們讓itemView調用requestFocus()方法或者requestFocusFromTouch()方法,這時itemView獲取了焦點,但是ListView沒有獲取焦點,這說明一個視圖中隻能有一個view獲取焦點。

去掉itemView的android:focusableInTouchMode="true"屬性,調用requestFocusFromTouch()方法,可以強製使itemViw獲取焦點。ListView依舊沒有獲取焦點。

 

總結:

1. 當使用導航鍵上下左右滾動時,android框架會自動讓view獲取焦點(獲取焦點後,就會高亮顯示),然而當用戶用手觸摸屏幕的時候,就不需要讓view自動獲取焦點了,也就是說,當用戶點擊了屏幕上的某個控件時,該控件就沒有必要自動獲取焦點了,因為用戶知道自己操作的是哪個控件,當用戶觸摸手機屏幕,就會進入touch mode模式。

2. 在touch mode 模式下,有些控件是不會自動獲取焦點的,但是還有些控件會,通過isFocusableInTouchMode()可以知道該控件在該touch模式下能否獲得焦點,TextView是默認不能獲得焦點的,ListView默認能夠獲得焦點,EditText等文字編輯類控件都可以。通過設置android:focusableInTouchMode="true"貌似可以使view控件獲取焦點,但是實際上並不會是veiw控件獲取焦點,還需要手動調用requestFocusFromTouch()方法或者requestFocus()方法才能真正獲取焦點。這裏推薦使用requestFocusFromTouch()方法,即時不用設置android:focusableInTouchMode="true",也能強製使控件獲取焦點。

3. 獲取ListView中有那個控件獲取了焦點的方法

                mListView.findFocus();
                mListView.getFocusedChild();

 

4. 通過ListView的setItemsCanFocus(true)方法並不可以使ItemView在touch mode下可以獲取焦點,他隻是表明在由ListAdapter創建的視圖中,可包含能獲得焦點的項目。

滾動事件發生在touch事件的後麵,這種說法是不對的,通過實驗可以得到onScroll方法的執行是在touch事件之前的,並且每一次觸摸屏幕,先觸發這個方法,然後才觸發touch事件,此外,當我們第一次進入列表界麵時,onScroll方法也多次被調用,第一次是在執行onCreate方法時被調用,這事還沒有生成界麵,所以visibleItemCount參數為0,然後的幾次調用就有了界麵了,visibleItemCount也被賦予界麵上顯示的item的個數,顯示不全的也算。差不多有兩次,這兩次的調用也是不一樣的,看看這三次調用這個方法的不同

圖一:

image

圖二:

image

圖三:

image

 

當用手觸摸屏幕上的某一項時,也會首先觸發這個方法,然後才是touch事件

image

通過重寫onTouch方法,可以實現當用戶觸摸屏幕的時候,itemView獲取焦點,並且變色,但是出現了兩個問題:

1. 如果ListView可以顯示多頁,可以看到每頁上又有一個ItemViw獲取了焦點,不知道為什麼?

推測:Adapter中getView方法的第二個蠶食convertView是複用的,估計是生成新的頁麵的時候複用了獲取焦點的veiw,這裏還要看源碼

 

2. 當滾動到非第一頁的時候,觸發屏幕,並不能使觸發點所在的ItemView獲取焦點?

ListView的getChildAt(int index)方法的參數index,與Adapter的getView方法的第一個參數position是不一樣的,每個界麵顯示幾個item,就建立從0到界麵顯示個數的索引,比如一個屏幕上顯示8條記錄,那麼索引就是

0---7,翻頁了,仍然會建立類似的索引,因此應該計算出觸發點的item在屏幕上的索引。

int x = (int) event.getX();
int y = (int) event.getY();
int position = mListView.pointToPosition(x, y);
int firstVisiblePosition = mListView.getFirstVisiblePosition();
view = mListView.getChildAt(position-firstVisiblePosition);

最後更新:2017-04-02 06:52:03

  上一篇:go MongoDB代碼中的StringBuilder類
  下一篇:go MYSQL 存儲過程和函數 案例 例子