ViewPager

来源:互联网 发布:下载福州网络家长学校 编辑:程序博客网 时间:2024/06/06 03:22

ViewPager是Android提供的视图切换的工具类,继承自ViewGroup,可实现Android页面的广告轮播,首次使用广告引导等。

ViewPager是Android V4扩展包中的类,使用时注意
1.Viewpager继承自ViewGroup,所以它是个容器,可以自由添加View类
2.需要一个适配器提供数据
3.Viewpager常配合Fragment使用

1.Viewpager适配器
PagerAdapter,和ListView等控件使用一样,需要ViewPager设置PagerAdapter来完成页面和数据的绑定,PagerAdapter是一个基类适配器,我们经常用它来实现app引导图,它的子类有FragmentPagerAdapterFragmentStatePagerAdapter,这两个子类适配器用于和Fragment一起使用。

  • PagerAdapter
public class AdapterViewpager extends PagerAdapter {    private List<View> mViewList;    public AdapterViewpager(List<View> mViewList) {        this.mViewList = mViewList;    }    @Override    public int getCount() {//必须实现        return mViewList.size();    }    @Override    public boolean isViewFromObject(View view, Object object) {//必须实现        return view == object;    }    @Override    public Object instantiateItem(ViewGroup container, int position) {//必须实现,实例化        container.addView(mViewList.get(position));        return mViewList.get(position);    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {//必须实现,销毁        container.removeView(mViewList.get(position));    }}

上面的四个方法必须实现

  • FragmentPagerAdapter
public class AdapterFragment extends FragmentPagerAdapter {    private List<Fragment> mFragments;    public AdapterFragment(FragmentManager fm, List<Fragment> mFragments) {        super(fm);        this.mFragments = mFragments;    }    @Override    public Fragment getItem(int position) {//必须实现        return mFragments.get(position);    }    @Override    public int getCount() {//必须实现        return mFragments.size();    }    @Override    public CharSequence getPageTitle(int position) {//选择性实现        return mFragments.get(position).getClass().getSimpleName();    }}
  • FragmentStatePagerAdapter和FragmentPagerAdapter实现一样,不再赘述

三种适配器的区别在于:

PagerAdapter是通用的适配器,FragmentPagerAdapter和FragmentStatePagerAdapter更专注于每一页是Fragment的情况,而这两个子类适配器使用情况也有区别

通过源码分析(节选):

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));        }        if (fragment != mCurrentPrimaryItem) {            fragment.setMenuVisibility(false);            fragment.setUserVisibleHint(false);        }        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);/*注意这里使用了detach,据源码注释解释理解:Detach the given fragment from the UI.  This is the same state as when it is put on the back stack: the fragment is removed from the UI, however its state is still being actively managed by the fragment manager.  When going into this state its view hierarchy is destroyed.大意是不显示视图,但依然归actively managed*/    }

FragmentStatePagerAdapter

@Override    public Object instantiateItem(ViewGroup container, int position) {        // If we already have this item instantiated, there is nothing        // to do.  This can happen when we are restoring the entire pager        // from its saved state, where the fragment manager has already        // taken care of restoring the fragments we previously had instantiated.        if (mFragments.size() > position) {            Fragment f = mFragments.get(position);            if (f != null) {                return f;            }        }        if (mCurTransaction == null) {            mCurTransaction = mFragmentManager.beginTransaction();        }        Fragment fragment = getItem(position);        if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);        if (mSavedState.size() > position) {            Fragment.SavedState fss = mSavedState.get(position);            if (fss != null) {                fragment.setInitialSavedState(fss);            }        }        while (mFragments.size() <= position) {            mFragments.add(null);        }        fragment.setMenuVisibility(false);        fragment.setUserVisibleHint(false);        mFragments.set(position, fragment);        mCurTransaction.add(container.getId(), fragment);        return fragment;    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        Fragment fragment = (Fragment) object;        if (mCurTransaction == null) {            mCurTransaction = mFragmentManager.beginTransaction();        }        if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object                + " v=" + ((Fragment)object).getView());        while (mSavedState.size() <= position) {            mSavedState.add(null);        }        mSavedState.set(position, fragment.isAdded()                ? mFragmentManager.saveFragmentInstanceState(fragment) : null);        mFragments.set(position, null);// 这里设置为null,mFragments ——> ArrayList.set(int index, E element);        mCurTransaction.remove(fragment);    }

根据以上分析,FragmentPagerAdapter适合在fragment中页面较少的情况下使用,FragmentStatePagerAdapter适合在页面较多的情况下使用,省内存

2.Viewpager翻页动画

Viewpager提供了PageTransformer接口用于实现翻页动画

实现翻页动画的关键就是重写transformPage方法
方法里有两个参数 view 和 position, 理解这两个参数非常重要。

    /**     * A PageTransformer is invoked whenever a visible/attached page is scrolled.     * This offers an opportunity for the application to apply a custom transformation     * to the page views using animation properties.     *     * <p>As property animation is only supported as of Android 3.0 and forward,     * setting a PageTransformer on a ViewPager on earlier platform versions will     * be ignored.</p>     */    public interface PageTransformer {        /**         * Apply a property transformation to the given page.         *         * @param page Apply the transformation to this page         * @param position Position of page relative to the current front-and-center         *                 position of the pager. 0 is front and center. 1 is one full         *                 page position to the right, and -1 is one page position to the left.         */        void transformPage(View page, float position);    }

假设有三个页面view1,view2,view3从左至右在viewPager中显示

往左滑动时:view1,view2,view3的position都是不断变小的。

               view1的position: 0 → -1 → 负无穷大               view2的position: 1 → 0 → -1                view3的position: 1 → 0

往右滑动时:view1,view2,view3的position都是不断变大的。

               view1的position: -1 → 0                view2的position: -1 → 0 → 1                view3的position: 0 → 1→ 正无穷大

当position是正负无穷大时view就离开屏幕视野了。因此最核心的控制逻辑是在[-1,0]和(0,1]这两个区间,通过设置透明度,平移,旋转,缩放等动画组合可以实现各式各样的页面变化效果。

两个例子

public class DepthPageTransformer implements ViewPager.PageTransformer {    private static final float MIN_SCALE = 0.75f;    public void transformPage(View view, float position) {        Log.d("DepthPageTransformer", view.getTag() + " , " + position + "");        int pageWidth = view.getWidth();        if (position < -1) { // [-Infinity,-1)            // This page is way off-screen to the left.            view.setAlpha(0);        } else if (position <= 0) { // [-1,0]            // Use the default slide transition when moving to the left page            view.setAlpha(1);            view.setTranslationX(0);            view.setScaleX(1);            view.setScaleY(1);        } else if (position <= 1) { // (0,1]            // Fade the page out.            view.setAlpha(1 - position);            // Counteract the default slide transition            view.setTranslationX(pageWidth * -position);            // Scale the page down (between MIN_SCALE and 1)            float scaleFactor = MIN_SCALE                    + (1 - MIN_SCALE) * (1 - Math.abs(position));            view.setScaleX(scaleFactor);            view.setScaleY(scaleFactor);        } else { // (1,+Infinity]            // This page is way off-screen to the right.            view.setAlpha(0);        }    }}
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {    private static final float MIN_SCALE = 0.85f;    private static final float MIN_ALPHA = 0.5f;    @SuppressLint("NewApi")    public void transformPage(View view, float position) {        int pageWidth = view.getWidth();        int pageHeight = view.getHeight();        Log.e("TAG", view + " , " + position + "");        if (position < -1) { // [-Infinity,-1)            // This page is way off-screen to the left.            view.setAlpha(0);        } else if (position <= 1)         { // [-1,1]            // Modify the default slide transition to shrink the page as well            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));            float vertMargin = pageHeight * (1 - scaleFactor) / 2;            float horzMargin = pageWidth * (1 - scaleFactor) / 2;            if (position < 0) {                view.setTranslationX(horzMargin - vertMargin / 2);            } else {                view.setTranslationX(-horzMargin + vertMargin / 2);            }            // Scale the page down (between MIN_SCALE and 1)            view.setScaleX(scaleFactor);            view.setScaleY(scaleFactor);            // Fade the page relative to its size.            view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)                    / (1 - MIN_SCALE) * (1 - MIN_ALPHA));        } else { // (1,+Infinity]            // This page is way off-screen to the right.            view.setAlpha(0);        }    }}

3.Viewpager指示器

有一个开源项目供参考

项目github地址:
https://github.com/ongakuer/CircleIndicator

0 0
原创粉丝点击