Android ListView position詳解及實(shí)例代碼
我們?cè)谑褂肔istView的時(shí)候,一般都會(huì)為L(zhǎng)istView添加一個(gè)響應(yīng)事件android.widget.AdapterView.OnItemClickListener。對(duì)OnItemClickListener的position和id參數(shù),我相信有些人在這上面走了些彎路。
在使用listview的時(shí)候,我們經(jīng)常會(huì)在listview的監(jiān)聽(tīng)事件中,例如OnItemClickListener(onItemClick)中,或listview的adapter中(getView、getItem、getItemId等)看到position這個(gè)變量。在我們沒(méi)有為listview添加headerView時(shí),position和數(shù)據(jù)源集合的索引是一致的,當(dāng)添加了headerView之后,某些地方的position值就會(huì)發(fā)生變化,如果不理解清楚,經(jīng)常會(huì)犯一些糊涂。
在listview添加了headerView后, 會(huì)將所有view交給HeaderViewListAdapter來(lái)處理,所以我們要在setAdapter之前添加headerView或footerView,否則將顯示不出來(lái)。
@Override 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; }
先看看HeaderListAdapter中幾個(gè)帶position參數(shù)的方法實(shí)現(xiàn),我們可以看到在傳出的position為adjPosition,而adjPosition均為我們自動(dòng)去掉了headerView的數(shù)量,所以adapter中幾個(gè)帶position變量的方法,得到的position值均和數(shù)據(jù)源集合索引一致,仔細(xì)翻看HeaderListAdapter中所有需要傳出position的方法,position的值都是自動(dòng)減去了headerView數(shù)量。
public View getView(int position, View convertView, ViewGroup parent) { // Header (negative positions will throw an ArrayIndexOutOfBoundsException) int numHeaders = getHeadersCount(); if (position < numHeaders) { return mHeaderViewInfos.get(position).view; } // Adapter final int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getCount(); if (adjPosition < adapterCount) { return mAdapter.getView(adjPosition, convertView, parent); } } // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException) return mFooterViewInfos.get(adjPosition - adapterCount).view; }
public Object getItem(int position) { // Header (negative positions will throw an ArrayIndexOutOfBoundsException) int numHeaders = getHeadersCount(); if (position < numHeaders) { return mHeaderViewInfos.get(position).data; } // Adapter final int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getCount(); if (adjPosition < adapterCount) { return mAdapter.getItem(adjPosition); } } // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException) return mFooterViewInfos.get(adjPosition - adapterCount).data; } public long getItemId(int position) { int numHeaders = getHeadersCount(); if (mAdapter != null && position >= numHeaders) { int adjPosition = position - numHeaders; int adapterCount = mAdapter.getCount(); if (adjPosition < adapterCount) { return mAdapter.getItemId(adjPosition); } } return -1; }
我們?cè)賮?lái)分析分析OnItemClickListener的相關(guān)源碼,OnItemClickListener在android.widget.AdapterView的public boolean performItemClick(View view, int position, long id)函數(shù)中被調(diào)用。而performItemClick是在android.widget.AbsListView.PerformClick.run() 中被調(diào)用:
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_POSITION && 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對(duì)應(yīng)motionPosition,而motionPosition通過(guò)調(diào)試,我們發(fā)現(xiàn)就是listview中被點(diǎn)擊的位置,所以我們經(jīng)常在onItemClick中需要獲取數(shù)據(jù)源集合中某個(gè)item時(shí),會(huì)習(xí)慣性寫(xiě)這樣代碼:sourceList.get(position-listView.getHeaderViewsCount())。
我們發(fā)現(xiàn)onItemClick還有一個(gè)參數(shù),其實(shí)就是上面源碼中傳遞給performItemClick的第三個(gè)參數(shù),而第三個(gè)參數(shù)是通過(guò)調(diào)用adapter的getItemId將motionPosition減去了headerView的數(shù)量,所以這個(gè)參數(shù)的結(jié)果是與數(shù)據(jù)源集合的索引一致的。也就是說(shuō),我們完全可以使用onItemClick的id這個(gè)參數(shù),這個(gè)參數(shù)是和數(shù)據(jù)源集合的索引一致的。
另外我們需要注意,如果數(shù)據(jù)源沒(méi)有內(nèi)容,則id的值會(huì)為-1,所以我們?cè)谑褂胕d時(shí),需要對(duì)id做適當(dāng)判斷。
總結(jié):在OnItemClickListener的onItemClick方法中,當(dāng)我們需要獲取點(diǎn)擊listview對(duì)應(yīng)的數(shù)據(jù)源索引時(shí),使用id參數(shù)即可。另外除了onItemClick的position參數(shù)是點(diǎn)擊listview對(duì)應(yīng)view的位置外,adapter中所有position均為數(shù)據(jù)源索引位置。其實(shí)換個(gè)角度更容易記,在listview中,position理應(yīng)是listview中view對(duì)應(yīng)的位置,而在adapter中,理應(yīng)是數(shù)據(jù)源的索引位置。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- Android 修改系統(tǒng)關(guān)機(jī)動(dòng)畫(huà)的實(shí)現(xiàn)
- Android仿斗魚(yú)直播的彈幕效果
- Android中轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的實(shí)現(xiàn)與兼容性處理
- Android 矩陣ColorMatrix
- Android跳轉(zhuǎn)到通訊錄獲取用戶名稱(chēng)和手機(jī)號(hào)碼的實(shí)現(xiàn)思路
- Android中關(guān)于遞歸和二分法的算法實(shí)例代碼
- Android ListView ImageView實(shí)現(xiàn)單選按鈕實(shí)例
相關(guān)文章
Android 解決使用SearchView時(shí)軟鍵盤(pán)不支持actionSearch的問(wèn)題
本文主要介紹使用SearchView時(shí)軟鍵盤(pán)不支持actionSearch,這里提供了解決方案,希望能幫助開(kāi)發(fā)Android應(yīng)用的同學(xué)2016-07-07在RecyclerView中實(shí)現(xiàn)button的跳轉(zhuǎn)功能
本次實(shí)驗(yàn)就是在RecyclerView中添加一個(gè)button控件并實(shí)現(xiàn)監(jiān)聽(tīng),使鼠標(biāo)點(diǎn)擊時(shí)可以跳轉(zhuǎn)到另外一個(gè)設(shè)計(jì)好的界面,對(duì)RecyclerView實(shí)現(xiàn)button跳轉(zhuǎn)功能感興趣的朋友一起看看吧2021-10-10Eclipse+ADT+Android SDK搭建安卓開(kāi)發(fā)環(huán)境的實(shí)現(xiàn)步驟
這篇文章主要介紹了Eclipse+ADT+Android SDK搭建安卓開(kāi)發(fā)環(huán)境的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Android編程實(shí)現(xiàn)的手寫(xiě)板和涂鴉功能
這篇文章主要介紹了Android編程實(shí)現(xiàn)的手寫(xiě)板和涂鴉功能,涉及Android界面布局及圖形繪制功能相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-01-01Android自定義view制作抽獎(jiǎng)轉(zhuǎn)盤(pán)
這篇文章主要為大家詳細(xì)介紹了Android自定義view制作抽獎(jiǎng)轉(zhuǎn)盤(pán),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12