編輯:關於Android編程
我們在使用ListView的時候,一般都會為ListView添加一個響應事件android.widget.AdapterView.OnItemClickListener。本文主要在於對OnItemClickListener的position和id參數做詳細的解釋,我相信有些人在這上面走了些彎路。
先來看一下官方的文檔
position The position of the view in the adapter.
id The row id of the item that was clicked.
而這兩行字並沒有解釋清楚position和id的區別。另外,我們還有個Adapter的getView方法。
public abstract View getView (int position, View convertView, ViewGroup parent)
這裡也有一個position。
初步接觸ListView的同學,一般會直接繼承ArrayAdapter,然後(比如我),就想當然的認為OnItemClick的position和getView的position是一樣的啊。於是我們就getItem(position)來獲取相應的數據。
那麼這段代碼有沒有錯呢?如果有錯的話,在什麼情況會出錯呢?
第一個問題的答案是,當我們為ListView添加headerView或者footerView之後,這段代碼就不一定是我們想要的了。
出現問題的原因在於,當我們為ListView添加headerView或者footerView之後,ListView在setAdapter時,做了一些事情,這導致,Adapter和OnItemClickListener中的position含義發生了變化。
我們可以來看看ListView中setAdapter的實現
public void setAdapter(ListAdapter adapter) { if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } resetList(); mRecycler.clear(); if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; }
可以看出,如果這個ListView存在headerView或者footerView的話,那麼會在我們傳入的adapter外面在封裝一層HeaderViewListAdapter,這是一個專門用來自動處理headerView和footerView的adapter。在ListView中,本身不區分headerView,footerView。ListView可以理解成是只負責管理一組View的數組的UI(ViewGroup),headerView和footerView都委托給HeaderViewListAdapter來處理。(從這裡也可以看到為什麼API文檔中提到,addFooterView和addHeaderView要在setAdapter函數之前調用,如果在之後調用,那麼就不會生成HeaderViewListAdapter,從而導致顯示不出headerView和footerView)。
回到開頭的問題,position和id有啥區別。為此,我們找一下position和id是怎麼傳進來的。
OnItemClickListener在android.widget.AdapterView的public boolean performItemClick(View view, int position, long id)函數中被調用。
performItemClick在android.widget.AbsListView.PerformClick.run() 中被調用
private class PerformClick extends WindowRunnnable implements Runnable { int mClickMotionPosition; public void run() { // The data has changed since we posted this action in the event queue, // bail out before bad things happen if (mDataChanged) return; final ListAdapter adapter = mAdapter; final int motionPosition = mClickMotionPosition; if (adapter != null && mItemCount > 0 && motionPosition != INVALID_<strong>POSITION</strong> && motionPosition < adapter.getCount() && sameWindow()) { final View view = getChildAt(motionPosition - mFirstPosition); // If there is no view, something bad happened (the view scrolled off the // screen, etc.) and we should cancel the click if (view != null) { performItemClick(view, motionPosition, adapter.getItemId(motionPosition)); } } } }
可以看到,position事實上就是ListView中被點擊的view的位置。注意,在ListView中是不負責處理headerView和footViewer的,所以,這個位置應該是這個被點擊的view在數組[所有的headerView,用戶添加的view,所有的footerView]中的位置(請自行參考HeaderViewListAdapter的getView實現)。而id是來自於adapter.getItemId(position)。
對於ArrayAdapter的getItemId函數,實現就是return position。id和position是一致的。
然而,對於HeaderViewListAdapter
public long getItemId(int <strong>position</strong>) { int numHeaders = getHeadersCount(); if (mAdapter != null && <strong>position</strong> >= numHeaders) { int adjPosition = <strong>position</strong> - numHeaders; int adapterCount = mAdapter.getCount(); if (adjPosition < adapterCount) { return mAdapter.getItemId(adjPosition); } } return -1; }
實現邏輯是,如果position指向了headerView或footerView,那麼返回-1,否則,將返回在用戶view數組的位置。
也就是說
id=position-headerView的個數(id < headerviewer的個數+用戶view的個數),否則=-1
因此,OnItemClickListener的正確實現如下:
void onItemClick(AdapterViewparent, View view, int <strong>position</strong>, long id){ if(id == -1) { // 點擊的是headerView或者<strong>footerView</strong> return; } int realPosition=(int)id; T item=getItem(realPosition); // 響應代碼 }
相關閱讀:
Android 中ListView setOnItemClickListener點擊無效原因分析
以上所述是小編給大家介紹的Android ListView的OnItemClickListener詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對本站網站的支持!
有些日子沒寫博客了,當然這段時間也比較忙,大家見諒,好了,話不多說,開始學習吧。我們繼續學習IO流,還有幾個知識點沒有學。操作基本數據類型的流操作基本數據類型DataIn
上面一篇博客,介紹了Studio的優點與1.0 RC的安裝與上手體驗,沒想到google的更新速度這麼快,已經出了RC 2版本,主要是修復一些bug。那麼今天就帶大家預覽
前言最近要實現個圓角邊框的對話框設計圖,查了網上很多種實現,都差不多,從中得到靈感,實現了另一種方式,利用layer-list:先來看看實現的效果如下:首先在drawab
昨天群裡有討論時間軸的項目,沒有接觸過,以為很吊,研究之後才知道表面都是忽悠人的,使用listview就能實現了,也沒有什麼新鮮的東西 廢話少說,直接上圖