@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//测量ViewPager自身大小
setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
getDefaultSize(0, heightMeasureSpec));
final int measuredWidth = getMeasuredWidth();
// child的宽高,占满父控件
int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight();
int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
//1.测量Decor
int size = getChildCount();
for (int i = 0; i < size; ++i) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp != null && lp.isDecor) {//仅对Decor进行测量
//省略若干代码,主要负责对Decor控件的测量
...
}
}
}
mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY);
// 2.从Adapter中获取childView
mInLayout = true;
populate();
mInLayout = false;
// 3.测量非Decor的childView
size = getChildCount();
for (int i = 0; i < size; ++i) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp == null || !lp.isDecor) {
final int widthSpec = MeasureSpec.makeMeasureSpec(
(int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY);
child.measure(widthSpec, mChildHeightMeasureSpec);
}
}
}
}
#layout.xml <ViewPager> <DecorView /> </ViewPager>
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (!checkLayoutParams(params)) {
params = generateLayoutParams(params);
}
final LayoutParams lp = (LayoutParams) params;
lp.isDecor |= child instanceof Decor; //在此处给isDecor赋值
//省略无关代码
...
}
public class AutoScrollAdapter extends PagerAdapter {
//省略构造方法代码
...
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
@Override
public int getCount() {
return mData.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View itemView = new TextView(mContext); //通过各种方法新建一个childView
container.addView(itemView);//将childView添加到ViewPager中
return itemView;
}
}
static class ItemInfo {
Object object; //childView
int position; //childView在Adapter中的位置
boolean scrolling; //是否在滚动
float widthFactor; //宽度的倍数,默认情况下是1
float offset; //页面的偏移参数,粗暴的理解就是第几个页面
}
void populate(int newCurrentItem) {
ItemInfo oldCurInfo = null;
int focusDirection = View.FOCUS_FORWARD;
if (mCurItem != newCurrentItem) {
focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
oldCurInfo = infoForPosition(mCurItem); //获取旧的ItemInfo对象
mCurItem = newCurrentItem; //更新mCurItem的值,就是在Adapter中的position
}
//省略无关代码
...
//mOffscreenPageLimit就是setOffscreenPageLimit方法设置的值
final int pageLimit = mOffscreenPageLimit;
//根据下面三行代码可知:mItems的长度就是 2 * pageLimit + 1
//这里声明的startPos和endPos在后面会起作用,大家注意一下
final int startPos = Math.max(0, mCurItem - pageLimit);
final int N = mAdapter.getCount();
final int endPos = Math.min(N-1, mCurItem + pageLimit);
// 遍历mItems列表,找出mCurItem对应的ItemInfo对象,是根据position来判断的
int curIndex = -1;
ItemInfo curItem = null;
for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
final ItemInfo ii = mItems.get(curIndex);
if (ii.position >= mCurItem) {
if (ii.position == mCurItem) curItem = ii;
break;
}
}
// 如果mItems中还未保存该ItemInfo,则创建一个IntemInfo对象
if (curItem == null && N > 0) {
curItem = addNewItem(mCurItem, curIndex);
}
...
ItemInfo addNewItem(int position, int index) {
ItemInfo ii = new ItemInfo(); //新建一个ItemInfo对象
ii.position = position;
ii.object = mAdapter.instantiateItem(this, position);//用Adapter创建一个childView
ii.widthFactor = mAdapter.getPageWidth(position);//默认返回1.0f
if (index < 0 || index >= mItems.size()) { //添加到mItems中
mItems.add(ii);
} else {
mItems.add(index, ii);
}
return ii;
}
if (curItem != null) {
//1.调整curItem左边的对象
float extraWidthLeft = 0.f;
// curIndex是curItem在mItems中的索引
// itemIndex就是curItem左边的ItemInfo的索引
int itemIndex = curIndex - 1;
//获取左边的ItemInfo对象
ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
final int clientWidth = getClientWidth();
//curItem左边需要的宽度,默认情况下为1.0f
final float leftWidthNeeded = clientWidth <= 0 ? 0 :
2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth;
//遍历mItems左半部分,即curIndex左边的对象
//只有在pos < startPos时才能退出循环,否则会一直遍历到pos=0
for (int pos = mCurItem - 1; pos >= 0; pos--) {
// 建议大家先从下面的else if开始看,因为这里的逻辑是准备退出循环了
if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
//当pos < startPos,说明mItems左边部分已经调整完毕了
//此时的ii代表的是,startPos左边的对象了
if (ii == null) {
break;
}
//如果startPos左边还有对象,需要从mItems中移除
if (pos == ii.position && !ii.scrolling) {
mItems.remove(itemIndex);
mAdapter.destroyItem(this, pos, ii.object);
itemIndex--;
curIndex--;
ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
}
//如果curIndex左边的ItemInfo对象不为null
} else if (ii != null && pos == ii.position) {
extraWidthLeft += ii.widthFactor; //累加curItem左边需要的宽度
itemIndex--; //再往curIndex左边移一个位置
ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; //取出ItemInfo对象
//如果curIndex左边的ItemInfo为null
} else {
//新建一个ItemInfo对象,添加到itemIndex的右边
ii = addNewItem(pos, itemIndex + 1);
extraWidthLeft += ii.widthFactor; //累加左边宽度
curIndex++; //由于往mItems中插入了一个对象,故curIndex需要加1
ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; //去除ItemInfo
}
}
//2.调整curItem右边的对象,逻辑与上面类似
//代码省略
...
// 3.计算mItems中的偏移参数
calculatePageOffsets(curItem, curIndex, oldCurInfo);
}
// 将ItemInfo的内容更新到childView的LayoutParams中
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.childIndex = i;
if (!lp.isDecor && lp.widthFactor == 0.f) {
final ItemInfo ii = infoForChild(child);
if (ii != null) {
lp.widthFactor = ii.widthFactor;
lp.position = ii.position;
}
}
}
//根据lp.position的大小对所有childView进行排序,另外DecorView是排在其他child之前的
sortChildDrawingOrder();
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
int width = r - l;
int height = b - t;
//1.布局Decor,根据lp.isDecor来筛选DecorView
//代码略
...
final int childWidth = width - paddingLeft - paddingRight;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
ItemInfo ii;
//此处将DecorView过滤掉,并且根据view从mItems中查找ItemInfo对象
//如果ViewPager布局中添加了未实现Decor接口的控件,将不会被布局
//因为无法从mItems中查找到ItemInfo对象
if (!lp.isDecor && (ii = infoForChild(child)) != null) {
//计算当前page的左边界偏移值,此处的offset会随着页面增加而增加
int loff = (int) (childWidth * ii.offset);
int childLeft = paddingLeft + loff;
int childTop = paddingTop;
if (lp.needsMeasure) {//如果需要重新测量,则重新测量之
lp.needsMeasure = false;
final int widthSpec = MeasureSpec.makeMeasureSpec(
(int) (childWidth * lp.widthFactor),
MeasureSpec.EXACTLY);
final int heightSpec = MeasureSpec.makeMeasureSpec(
(int) (height - paddingTop - paddingBottom),
MeasureSpec.EXACTLY);
child.measure(widthSpec, heightSpec);
}
//child调用自己的layout方法来布局自己
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(),
childTop + child.getMeasuredHeight());
}
}
}
mTopPageBounds = paddingTop;
mBottomPageBounds = height - paddingBottom;
mDecorChildCount = decorCount;
//如果是首次布局,则会调用scrollToItem方法
if (mFirstLayout) {
scrollToItem(mCurItem, false, 0, false);
}
mFirstLayout = false;
}
private void scrollToItem(int item, boolean smoothScroll, int velocity,
boolean dispatchSelected) {
final ItemInfo curInfo = infoForPosition(item);
int destX = 0;
if (curInfo != null) {
final int width = getClientWidth();
destX = (int) (width * Math.max(mFirstOffset,
Math.min(curInfo.offset, mLastOffset)));
}
if (smoothScroll) {
smoothScrollTo(destX, 0, velocity);
if (dispatchSelected) {
dispatchOnPageSelected(item);
}
} else {
if (dispatchSelected) { //是否需要分发OnPageSelected回调
dispatchOnPageSelected(item);
}
completeScroll(false);
scrollTo(destX, 0);
pageScrolled(destX);
}
}
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有