Android ListView position詳解及實例代碼
我們在使用ListView的時候,一般都會為ListView添加一個響應(yīng)事件android.widget.AdapterView.OnItemClickListener。對OnItemClickListener的position和id參數(shù),我相信有些人在這上面走了些彎路。
在使用listview的時候,我們經(jīng)常會在listview的監(jiān)聽事件中,例如OnItemClickListener(onItemClick)中,或listview的adapter中(getView、getItem、getItemId等)看到position這個變量。在我們沒有為listview添加headerView時,position和數(shù)據(jù)源集合的索引是一致的,當添加了headerView之后,某些地方的position值就會發(fā)生變化,如果不理解清楚,經(jīng)常會犯一些糊涂。
在listview添加了headerView后, 會將所有view交給HeaderViewListAdapter來處理,所以我們要在setAdapter之前添加headerView或footerView,否則將顯示不出來。
@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中幾個帶position參數(shù)的方法實現(xiàn),我們可以看到在傳出的position為adjPosition,而adjPosition均為我們自動去掉了headerView的數(shù)量,所以adapter中幾個帶position變量的方法,得到的position值均和數(shù)據(jù)源集合索引一致,仔細翻看HeaderListAdapter中所有需要傳出position的方法,position的值都是自動減去了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;
}
我們再來分析分析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對應(yīng)motionPosition,而motionPosition通過調(diào)試,我們發(fā)現(xiàn)就是listview中被點擊的位置,所以我們經(jīng)常在onItemClick中需要獲取數(shù)據(jù)源集合中某個item時,會習慣性寫這樣代碼:sourceList.get(position-listView.getHeaderViewsCount())。
我們發(fā)現(xiàn)onItemClick還有一個參數(shù),其實就是上面源碼中傳遞給performItemClick的第三個參數(shù),而第三個參數(shù)是通過調(diào)用adapter的getItemId將motionPosition減去了headerView的數(shù)量,所以這個參數(shù)的結(jié)果是與數(shù)據(jù)源集合的索引一致的。也就是說,我們完全可以使用onItemClick的id這個參數(shù),這個參數(shù)是和數(shù)據(jù)源集合的索引一致的。
另外我們需要注意,如果數(shù)據(jù)源沒有內(nèi)容,則id的值會為-1,所以我們在使用id時,需要對id做適當判斷。
總結(jié):在OnItemClickListener的onItemClick方法中,當我們需要獲取點擊listview對應(yīng)的數(shù)據(jù)源索引時,使用id參數(shù)即可。另外除了onItemClick的position參數(shù)是點擊listview對應(yīng)view的位置外,adapter中所有position均為數(shù)據(jù)源索引位置。其實換個角度更容易記,在listview中,position理應(yīng)是listview中view對應(yīng)的位置,而在adapter中,理應(yīng)是數(shù)據(jù)源的索引位置。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Android 解決使用SearchView時軟鍵盤不支持actionSearch的問題
本文主要介紹使用SearchView時軟鍵盤不支持actionSearch,這里提供了解決方案,希望能幫助開發(fā)Android應(yīng)用的同學2016-07-07
在RecyclerView中實現(xiàn)button的跳轉(zhuǎn)功能
本次實驗就是在RecyclerView中添加一個button控件并實現(xiàn)監(jiān)聽,使鼠標點擊時可以跳轉(zhuǎn)到另外一個設(shè)計好的界面,對RecyclerView實現(xiàn)button跳轉(zhuǎn)功能感興趣的朋友一起看看吧2021-10-10
Eclipse+ADT+Android SDK搭建安卓開發(fā)環(huán)境的實現(xiàn)步驟
這篇文章主要介紹了Eclipse+ADT+Android SDK搭建安卓開發(fā)環(huán)境的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09

