listView.getChildCount() 包含了headerView、footerView 以及 cellView,java
而 Adapter 的 getItemCount() 只包含數據項(對應cellView 的個數),app
因此若是有經過listview的childView 找對應的數據item的話,使用時須要注意計算ide
//在listview 的 adapter中 int cc = listView.getChildCount(); int headerCount = listView.getHeaderViewsCount(); //int footerCount = listView.getFooterViewsCount(); int itemCount = getCount(); for (int i = 0; i < cc; i++) { View child = listView.getChildAt(i); int tmp_pos = listView.getPositionForView(child); int position = tmp_pos - headerCount; if (position < 0 || position >= itemCount) { // 是headerView 或 footerView continue; } // 如今的position 纔對應adapter的數據項的index //能夠進行 getItemType(position) 等操做 }
緣由是在listview 內部會檢查是否有 header 或footer ,有的話會用一個 HeaderViewListAdapter 包咱們提供的listAdapter 包裝起來:this
@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; } mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; // AbsListView#setAdapter will update choice mode states. super.setAdapter(adapter); ... } ... public void addFooterView(View v, Object data, boolean isSelectable) { final FixedViewInfo info = new FixedViewInfo(); info.view = v; info.data = data; info.isSelectable = isSelectable; mFooterViewInfos.add(info); // Wrap the adapter if it wasn't already wrapped. if (mAdapter != null) { if (!(mAdapter instanceof HeaderViewListAdapter)) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter); } // In the case of re-adding a footer view, or adding one later on, // we need to notify the observer. if (mDataSetObserver != null) { mDataSetObserver.onChanged(); } } }
view的複用都體如今方法makeAndAddView調用的obtainView;
spa
保存了listView因爲非數據變化緣由致使layout時,其全部child view 保存在RecyleBin 的 mActiveView 中。code
用到的position參數 都是指adapter中數據項位置。server
private View makeAndAddView(int position, int y, boolean flowDown, boolean selected) { View child; onChildCreated(position, flowDown); if (!mDataChanged) { // Try to use an existing view for this position child = mRecycleBin.getActiveView(position); if (child != null) { setupChild(child, position, y, flowDown, selected, true); return child; } } child = obtainView(position, mIsScrap); setupChild(child, position, y, flowDown, selected, mIsScrap[0]); return child; }
obtainView:get
private View obtainView(int position, boolean[] isScrap) { isScrap[0] = false; View scrapView; scrapView = mRecycleBin.getScrapView(position); View child; if (scrapView != null) { child = mAdapter.getView(position, scrapView, this); if (child != scrapView) { mRecycleBin.addScrapView(scrapView, position); } else { isScrap[0] = true; } } else { child = mAdapter.getView(position, null, this); } return child; }
public Object instantiateItem(ViewGroup container, final int arg1) { container.addView(mViews.get(arg1),0); return mViews.get(arg1); }
在源碼的註釋裏清楚標註了這一點:源碼
在finishUpdate (ViewGroup) 方法返回前須要完成addView 操做it
/**
* Create the page for the given position. The adapter is responsible
* for adding the view to the container given here, although it only
* must ensure this is done by the time it returns from
* {@link #finishUpdate(ViewGroup)}.
*
* @param container The containing View in which the page will be shown.
* @param position The page position to be instantiated.
* @return Returns an Object representing the new page. This does not
* need to be a View, but can be some other container of the page.
*/
public Object instantiateItem(ViewGroup container, int position) {
return instantiateItem((View) container, position);
}
那麼 instantiateItem 返回的object 到底什麼意義呢?從ViewPager的代碼片斷能夠看出這個object就是(必須)view,它被ViewPager 包裝進ItemInfo來記錄view的信息:
static class ItemInfo { Object object; int position; boolean scrolling; float widthFactor; float offset; } ItemInfo infoForChild(View child) { for (int i=0; i<mItems.size(); i++) { ItemInfo ii = mItems.get(i); if (mAdapter.isViewFromObject(child, ii.object)) { return ii; } } return null; }