Android ListView position詳解及執行個體代碼_Android

來源:互聯網
上載者:User

 我們在使用ListView的時候,一般都會為ListView添加一個響應事件android.widget.AdapterView.OnItemClickListener。對OnItemClickListener的position和id參數,我相信有些人在這上面走了些彎路。

    在使用listview的時候,我們經常會在listview的監聽事件中,例如OnItemClickListener(onItemClick)中,或listview的adapter中(getView、getItem、getItemId等)看到position這個變數。在我們沒有為listview添加headerView時,position和資料來源集合的索引是一致的,當添加了headerView之後,某些地方的position值就會發生變化,如果不理解清楚,經常會犯一些糊塗。

  在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參數的方法實現,我們可以看到在傳出的position為adjPosition,而adjPosition均為我們自動去掉了headerView的數量,所以adapter中幾個帶position變數的方法,得到的position值均和資料來源集合索引一致,仔細翻看HeaderListAdapter中所有需要傳出position的方法,position的值都是自動減去了headerView數量。

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的相關源碼,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_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對應motionPosition,而motionPosition通過調試,我們發現就是listview中被點擊的位置,所以我們經常在onItemClick中需要擷取資料來源集合中某個item時,會習慣性寫這樣代碼:sourceList.get(position-listView.getHeaderViewsCount())。

  我們發現onItemClick還有一個參數,其實就是上面源碼中傳遞給performItemClick的第三個參數,而第三個參數是通過調用adapter的getItemId將motionPosition減去了headerView的數量,所以這個參數的結果是與資料來源集合的索引一致的。也就是說,我們完全可以使用onItemClick的id這個參數,這個參數是和資料來源集合的索引一致的。

  另外我們需要注意,如果資料來源沒有內容,則id的值會為-1,所以我們在使用id時,需要對id做適當判斷。

  總結:在OnItemClickListener的onItemClick方法中,當我們需要擷取點擊listview對應的資料來源索引時,使用id參數即可。另外除了onItemClick的position參數是點擊listview對應view的位置外,adapter中所有position均為資料來源索引位置。其實換個角度更容易記,在listview中,position理應是listview中view對應的位置,而在adapter中,理應是資料來源的索引位置。

感謝閱讀,希望能協助到大家,謝謝大家對本站的支援!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.