ViewPager的源码分析--TODO
2021-11-25
4 min read
这是在基于总的Fragment数量为5,并且第一次数据加载已经完成,从0的tab切换到2的tab的过程,limit为1,分析2的创建以及3的预加载,还有0的destory:
void populate(int newCurrentItem) {
//newCurrentItem =2
ViewPager.ItemInfo oldCurInfo = null;
if (mCurItem != newCurrentItem) {
//oldCurInfo = 0
oldCurInfo = infoForPosition(mCurItem);
//mCurItem = 2
mCurItem = newCurrentItem;
}
mAdapter.startUpdate(this);
//mOffscreenPageLimit = 1
final int pageLimit = mOffscreenPageLimit;
//startPos = 1
final int startPos = Math.max(0, mCurItem - pageLimit);
//n= 5
final int N = mAdapter.getCount();
//endPos = 3
final int endPos = Math.min(N - 1, mCurItem + pageLimit);
// Locate the currently focused item or add it if needed.
int curIndex = -1;
ViewPager.ItemInfo curItem = null;
// mItems.size() = 2 (0,1)
for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
final ViewPager.ItemInfo ii = mItems.get(curIndex);
if (ii.position >= mCurItem) {
if (ii.position == mCurItem) curItem = ii;
break;
}
}
//curIndex =2
if (curItem == null && N > 0) {
curItem = addNewItem(mCurItem, curIndex);
}
//把index =2的fragment加入了
// Fill 3x the available width or up to the number of offscreen
// pages requested to either side, whichever is larger.
// If we have no current item we have no work to do.
if (curItem != null) {
float extraWidthLeft = 0.f;
//itemIndex = 1
int itemIndex = curIndex - 1;
//拿到1的ItemInfo
ViewPager.ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
final int clientWidth = getClientWidth();
final float leftWidthNeeded = clientWidth <= 0 ? 0 :
2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth;
//pos = 1
for (int pos = mCurItem - 1; pos >= 0; pos--) {
if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
if (ii == null) {
break;
}
if (pos == ii.position && !ii.scrolling) {
mItems.remove(itemIndex);
mAdapter.destroyItem(this, pos, ii.object);
if (DEBUG) {
Log.i(TAG, "populate() - destroyItem() with pos: " + pos
+ " view: " + ((View) ii.object));
}
itemIndex--;
curIndex--;
ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
}
} else if (ii != null && pos == ii.position) {
extraWidthLeft += ii.widthFactor;
itemIndex--;
//在1的时候拿到0的ItemInfo
ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
} else {
ii = addNewItem(pos, itemIndex + 1);
extraWidthLeft += ii.widthFactor;
curIndex++;
ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
}
}
float extraWidthRight = curItem.widthFactor;
itemIndex = curIndex + 1;
if (extraWidthRight < 2.f) {
ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
final float rightWidthNeeded = clientWidth <= 0 ? 0 :
(float) getPaddingRight() / (float) clientWidth + 2.f;
for (int pos = mCurItem + 1; pos < N; pos++) {
if (extraWidthRight >= rightWidthNeeded && pos > endPos) {
if (ii == null) {
break;
}
if (pos == ii.position && !ii.scrolling) {
mItems.remove(itemIndex);
mAdapter.destroyItem(this, pos, ii.object);
if (DEBUG) {
Log.i(TAG, "populate() - destroyItem() with pos: " + pos
+ " view: " + ((View) ii.object));
}
ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
}
} else if (ii != null && pos == ii.position) {
extraWidthRight += ii.widthFactor;
itemIndex++;
ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
} else {
ii = addNewItem(pos, itemIndex);
itemIndex++;
extraWidthRight += ii.widthFactor;
ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
}
}
}
calculatePageOffsets(curItem, curIndex, oldCurInfo);
mAdapter.setPrimaryItem(this, mCurItem, curItem.object);
}
mAdapter.finishUpdate(this);
// Check width measurement of current pages and drawing sort order.
// Update LayoutParams as needed.
//3
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();
lp.childIndex = i;
if (!lp.isDecor && lp.widthFactor == 0.f) {
// 0 means requery the adapter for this, it doesn't have a valid width.
final ViewPager.ItemInfo ii = infoForChild(child);
if (ii != null) {
lp.widthFactor = ii.widthFactor;
lp.position = ii.position;
}
}
}
sortChildDrawingOrder();
if (hasFocus()) {
View currentFocused = findFocus();
ViewPager.ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
if (ii == null || ii.position != mCurItem) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
ii = infoForChild(child);
if (ii != null && ii.position == mCurItem) {
if (child.requestFocus(View.FOCUS_FORWARD)) {
break;
}
}
}
}
}
}