Android ListView position詳解及實(shí)例代碼
我們在使用ListView的時(shí)候,一般都會(huì)為ListView添加一個(gè)響應(yīng)事件android.widget.AdapterView.OnItemClickListener。對OnItemClickListener的position和id參數(shù),我相信有些人在這上面走了些彎路。
在使用listview的時(shí)候,我們經(jīng)常會(huì)在listview的監(jiān)聽事件中,例如OnItemClickListener(onItemClick)中,或listview的adapter中(getView、getItem、getItemId等)看到position這個(gè)變量。在我們沒有為listview添加headerView時(shí),position和數(shù)據(jù)源集合的索引是一致的,當(dāng)添加了headerView之后,某些地方的position值就會(huì)發(fā)生變化,如果不理解清楚,經(jīng)常會(huì)犯一些糊涂。
在listview添加了headerView后, 會(huì)將所有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中幾個(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;
}
我們再來分析分析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中被點(diǎn)擊的位置,所以我們經(jīng)常在onItemClick中需要獲取數(shù)據(jù)源集合中某個(gè)item時(shí),會(huì)習(xí)慣性寫這樣代碼:sourceList.get(position-listView.getHeaderViewsCount())。
我們發(fā)現(xiàn)onItemClick還有一個(gè)參數(shù),其實(shí)就是上面源碼中傳遞給performItemClick的第三個(gè)參數(shù),而第三個(gè)參數(shù)是通過調(diào)用adapter的getItemId將motionPosition減去了headerView的數(shù)量,所以這個(gè)參數(shù)的結(jié)果是與數(shù)據(jù)源集合的索引一致的。也就是說,我們完全可以使用onItemClick的id這個(gè)參數(shù),這個(gè)參數(shù)是和數(shù)據(jù)源集合的索引一致的。
另外我們需要注意,如果數(shù)據(jù)源沒有內(nèi)容,則id的值會(huì)為-1,所以我們在使用id時(shí),需要對id做適當(dāng)判斷。
總結(jié):在OnItemClickListener的onItemClick方法中,當(dāng)我們需要獲取點(diǎn)擊listview對應(yīng)的數(shù)據(jù)源索引時(shí),使用id參數(shù)即可。另外除了onItemClick的position參數(shù)是點(diǎn)擊listview對應(yīng)view的位置外,adapter中所有position均為數(shù)據(jù)源索引位置。其實(shí)換個(gè)角度更容易記,在listview中,position理應(yīng)是listview中view對應(yīng)的位置,而在adapter中,理應(yīng)是數(shù)據(jù)源的索引位置。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Android EditText實(shí)現(xiàn)輸入金額類型詳解
EditText是Android中一個(gè)非常實(shí)用的控件,有很多InputType,可以來達(dá)到不同的輸入效果,下面這篇文章主要給大家介紹了關(guān)于Android EditText實(shí)現(xiàn)輸入金額類型的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-09-09
Flutter實(shí)現(xiàn)App功能引導(dǎo)頁
這篇文章主要為大家詳細(xì)介紹了Flutter實(shí)現(xiàn)App功能引導(dǎo)頁,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
Android應(yīng)用中仿今日頭條App制作ViewPager指示器
這篇文章主要介紹了Android應(yīng)用中仿今日頭條App制作ViewPager指示器的例子,一般就是導(dǎo)航條在翻頁時(shí)的動(dòng)態(tài)字體變色效果,需要的朋友可以參考下2016-04-04
Android Studio 運(yùn)行按鈕灰色的完美解決方法
今天新建項(xiàng)目的時(shí)候突然發(fā)現(xiàn)編譯后運(yùn)行按鈕為灰色,今天小編給大家?guī)砹薃ndroid Studio 運(yùn)行按鈕灰色的完美解決方法,非常不錯(cuò),對大家的需要或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2020-10-10
Android中ExpandableListView的用法實(shí)例
這篇文章主要介紹了Android中ExpandableListView的用法,以實(shí)例形式展示了Android中的下拉list控件的用法,需要的朋友可以參考下2014-10-10

