ListView position

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

  在listview添加了headerView後, 會將全部view交給HeaderViewListAdapter來處理,因此咱們要在setAdapter以前添加headerView或footerView,不然將顯示不出來。app

@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數量。ide

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())。post

  咱們發現onItemClick還有一個參數,其實就是上面源碼中傳遞給performItemClick的第三個參數,而第三個參數是經過調用adapter的getItemId將motionPosition減去了headerView的數量,因此這個參數的結果是與數據源集合的索引一致的。也就是說,咱們徹底能夠使用onItemClick的id這個參數,這個參數是和數據源集合的索引一致的。this

  另外咱們須要注意,若是數據源沒有內容,則id的值會爲-1,因此咱們在使用id時,須要對id作適當判斷。spa

  總結:在OnItemClickListener的onItemClick方法中,當咱們須要獲取點擊listview對應的數據源索引時,使用id參數便可。另外除了onItemClick的position參數是點擊listview對應view的位置外,adapter中全部position均爲數據源索引位置。其實換個角度更容易記,在listview中,position理應是listview中view對應的位置,而在adapter中,理應是數據源的索引位置。調試

相關文章
相關標籤/搜索