ViewPager简单实现分析
来源:互联网 发布:如何创建域名 编辑:程序博客网 时间:2024/05/29 20:00
public void setAdapter(PagerAdapter adapter) { final PagerAdapter oldAdapter = mAdapter; mAdapter = adapter; mExpectedAdapterCount = 0; if (mAdapter != null) { if (mObserver == null) { mObserver = new PagerObserver(); } mAdapter.registerDataSetObserver(mObserver); populate(); } }void populate() { populate(mCurItem); }void populate(int newCurrentItem) { ItemInfo oldCurInfo = null; int focusDirection = View.FOCUS_FORWARD; mAdapter.startUpdate(this);// 默认空实现 final int pageLimit = mOffscreenPageLimit; final int startPos = Math.max(0, mCurItem - pageLimit); final int N = mAdapter.getCount(); final int endPos = Math.min(N-1, mCurItem + pageLimit); // Locate the currently focused item or add it if needed. int curIndex = -1; ItemInfo curItem = null; if (curItem == null && N > 0) { curItem = addNewItem(mCurItem, curIndex);// curIndex==0 } // 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; int itemIndex = curIndex - 1; 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; float extraWidthRight = curItem.widthFactor;// extraWidthRight==1 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);// 猜测应该走这一步,添加所有item到数组中 itemIndex++; extraWidthRight += ii.widthFactor; ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; } } } calculatePageOffsets(curItem, curIndex, oldCurInfo); } // Check width measurement of current pages and drawing sort order. // Update LayoutParams as needed. final int childCount = getChildCount();// 之前调用adapter的instantiateItem(ViewGroup, int)添加了view 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) { // 0 means requery the adapter for this, it doesn't have a valid width. final ItemInfo ii = infoForChild(child);// 获取view对应的ItemInfo if (ii != null) { lp.widthFactor = ii.widthFactor; lp.position = ii.position; } } } sortChildDrawingOrder(); if (hasFocus()) { View currentFocused = findFocus(); 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(focusDirection)) { break; } } } } } } ItemInfo addNewItem(int position, int index) {ItemInfo ii = new ItemInfo();ii.position = position;ii.object = mAdapter.instantiateItem(this, position);ii.widthFactor = mAdapter.getPageWidth(position);mItems.add(index, ii);// index==0return ii;}// 思路:和《艺术探索》中介绍的测量每个孩子的步骤类似@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // For simple implementation, our internal size is always 0. // We depend on the container to specify the layout size of // our view. We can't really know what it is since we will be // adding and removing different arbitrary views and do not // want the layout to change as this happens. setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec)); final int measuredWidth = getMeasuredWidth(); final int maxGutterSize = measuredWidth / 10; mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); // Children are just made to fill our space. int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight(); int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); /* * Make sure all children have been properly measured. Decor views first. * Right now we cheat and make this less complicated by assuming decor * views won't intersect. We will pin to edges based on gravity. */ 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) { final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; int widthMode = MeasureSpec.AT_MOST; int heightMode = MeasureSpec.AT_MOST; boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; if (consumeVertical) { widthMode = MeasureSpec.EXACTLY; } else if (consumeHorizontal) { heightMode = MeasureSpec.EXACTLY; } int widthSize = childWidthSize; int heightSize = childHeightSize; if (lp.width != LayoutParams.WRAP_CONTENT) { widthMode = MeasureSpec.EXACTLY; if (lp.width != LayoutParams.FILL_PARENT) { widthSize = lp.width; } } if (lp.height != LayoutParams.WRAP_CONTENT) { heightMode = MeasureSpec.EXACTLY; if (lp.height != LayoutParams.FILL_PARENT) { heightSize = lp.height; } } final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); child.measure(widthSpec, heightSpec); if (consumeVertical) { childHeightSize -= child.getMeasuredHeight(); } else if (consumeHorizontal) { childWidthSize -= child.getMeasuredWidth(); } } } } mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); // Make sure we have created all fragments that we need to have shown. mInLayout = true; populate(); mInLayout = false; // Page views next. size = getChildCount(); for (int i = 0; i < size; ++i) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child + ": " + mChildWidthMeasureSpec); 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); } } } }// 思路:把每个已经测量过的view进行布局@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); int width = r - l;// 此width等于屏幕宽度(默认) int height = b - t; int paddingLeft = getPaddingLeft(); int paddingTop = getPaddingTop(); int paddingRight = getPaddingRight(); int paddingBottom = getPaddingBottom(); final int scrollX = getScrollX(); final int childWidth = width - paddingLeft - paddingRight; // Page views. Do this once we have the right padding offsets from above. for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); ItemInfo ii; if (!lp.isDecor && (ii = infoForChild(child)) != null) { int loff = (int) (childWidth * ii.offset);// 计算偏移。childWidth等于屏幕宽度 int childLeft = paddingLeft + loff; int childTop = paddingTop; if (lp.needsMeasure) { // This was added during layout and needs measurement. // Do it now that we know what we're working with. 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(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }总结一:ViewPager和普通的PagerAdapter如何结合/** * 默认实现--默认List中成员是View类型 */@Overridepublic Object instantiateItem(ViewGroup viewGroup, int position) {// 向ViewPager中添加一个ImageViewImageView view = (ImageView) (getList().get(position));if (!(view instanceof View)) {throw new RuntimeException("List的成员view不是真正的View类型,请检查List数据!");}viewGroup.addView(view);// 把添加的ImageView返回回去return view;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {container.removeView((View) object);}分析:如上述代码所述,当instantiateItem的时候,viewGroup.addView(view);添加子view到ViewPager中,这样ViewPager构造出List<ItemInfo>来维护所有view的相关信息。当measure和layout的时候,把所有view添加到ViewPager这个ViewGroup中。这样完成了界面的绘制工作。事件:响应各种滑动事件总结二:ViewPager和FragmentPagerAdapter如何结合@Override public Object instantiateItem(ViewGroup container, int position) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } final long itemId = getItemId(position); // Do we already have this fragment? String name = makeFragmentName(container.getId(), itemId); Fragment fragment = mFragmentManager.findFragmentByTag(name); if (fragment != null) { if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); mCurTransaction.attach(fragment); } else { fragment = getItem(position); if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId));// 把当前Fragment添加到ViewGroup(也就是ViewPager) } return fragment; } @Override public void destroyItem(ViewGroup container, int position, Object object) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object + " v=" + ((Fragment)object).getView()); mCurTransaction.detach((Fragment)object); }分析:instantiateItem的时候Fragment利用ViewGroup(ViewPager),把Fragment添加到ViewGroup中(核心步骤)改变pager的时候,也销毁旧的fragment,并创建新的fragment,并添加到viewgroup来实现切换
0 0
- ViewPager简单实现分析
- ViewPager 简单分析
- ViewPager的简单实现
- viewpager的简单实现
- ViewPager简单实现
- ViewPager简单实现
- 简单的ViewPager实现
- viewPager的简单实现
- ViewPager简单实现
- Android ViewPager简单实现
- ViewPager实现源码分析
- viewpager的一个简单实现
- ViewPager实现简单滑页
- ViewPager图片切换简单实现
- ViewPager页面指示器简单实现
- ViewPager+TabLayout滑动简单实现
- Tablayout+Viewpager+recyclerview简单实现
- 使用ViewPager实现简单滑页
- 平述factory reset——从main system到重引导流程
- 单例模式Singleton
- QtQuick 全局缩放和放大<DPI>
- Jump to Section Overview Usage Floating Action Icons Design Support Library Animating the Floating A
- Delete files or directories in bash shell
- ViewPager简单实现分析
- 为什么基于DNS的全局负载均衡(GSLB)不起作用?
- 【网络编程2】Java数据报套接字
- R语言︱线性混合模型理论与案例探究(固定效应&随机效应)
- leetcode-Ugly Number(丑数)
- 【Windows】教你一步一步在Windows 7 系统上开启Telnet服务
- Xcode各版本官方下载及百度云盘下载, Mac和IOS及Xcode版本历史.
- UVa 1347 Tour
- Android学习笔记之SimpleAdapter