ViewPager,OnPageChangeListener及PageTransformer

ViewPager

        viewpager有一个setPageTransformer(),主要是用在viewpager在滑动时的回调,第一个参数一般为true。它的参数为PageTransformer变量。

PageTransformer

        参考

        它是一个接口,里面的方法只有一个transformPage(View view,float position)。参数含义分别是:当前的view,以及该view在viewpager中的位置。不同的view,position的值是不同的。

        停止滑动后,显示在屏幕中的view的position为0。往左滑时,该view的position会随着滑动的移动而逐渐降低到-1;往后滑时,position会随着滑动逐渐增加到1。position的值大于1,或者小于-1,那么该position已经不可见。

        viewpager会保留当前屏幕,左边及右边一共3个view。超出1,那就代表该view是右边往右,小于-1就代表该view是左边往左。示例如下:

@Override
    public void transformPage(View page, float position) {
        if(position < -1){//超出屏幕
            page.setScaleY(1);
        }else if(position < 0){//当前的左边控件 [-1,0] 越往左滑,position值越小
            page.setScaleY(1-Math.abs(position));
        }else if(position <=1 ){//当前的右边控件,[0,1]越往左滑,Position值越小
            float value = 1-Math.abs(position);
            page.setScaleY(value);
            page.setScaleX(value);
            page.setAlpha(value);
            page.setTranslationX(page.getWidth() * -position);
        }else{
            page.setScaleY(1);
        }
    }

3d旋转

        利用PageTransformer可以实现ViewPager在滑动过程中,左右两个view按3d的形式旋转。实现的主要逻辑是:在滑动过程中,左view沿着它的右边框绕y轴旋转,右view沿着它的左边框绕y轴旋转。如下:
@Override
    public void transformPage(View page, float position) {
        if(-1 <= position && position <= 0){
            page.setPivotX(page.getWidth());
            page.setPivotY(page.getHeight() / 2.0f);
            page.setRotationY(position * 90);
        }else if(position <= 1){
            page.setPivotX(0);
            page.setPivotY(page.getHeight() / 2.0f);
            page.setRotationY(90 * position);
        }
    }
        这里面在设置旋转的中心点时,用的是getWidth,而不是getRight。因为getRight指的是view在它的父view中的位置,对于非第一个view来说,getRight得到的值远远大于它的右边框。因此,这里面使用getWidth才能达到左view绕右边框旋转的目的。

ViewPager的adapter

        该adapter除了明着要求重写的两个方法,还需要重写

public void destroyItem(ViewGroup container, int position, Object object)<pre name="code" class="java">public Object instantiateItem(ViewGroup container, int position) 
 

一个简单的示例为:

@Override
            public int getCount() {
                return 4;
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView((View)object);
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                TextView t = new TextView(MainActivity.this);
                t.setText(position+"");
                t.setBackgroundColor(Color.BLUE);
                container.addView(t);
                return t;
            }

OnPageChangeListener

        单说onPageScrolled()方法。

        它的第一个参数为当前屏幕中最左边一个子View的position,从第一页滑动到第二页时值为0,从第二页滑动到第一页时,值还是0.

        它的第二个参数是从0到1之间变化的。从第一页到第二页时,从0到1; 从第二页到第一页时,值从1到0 。因此,可以通过判断它的值是否大于0.5知道当前是左滑还是右滑。

示例

        随着ViewPager的滑动,某一滑块还根据移动,并不是等ViewPager停止后,滑块才移动。代码如下:

public class MainActivity extends Activity {
    private float mPreOffset;
    private boolean isFirst = true;
    private int mLastPosition;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DisplayMetrics m = new DisplayMetrics();
        final View cursor = findViewById(R.id.cursor);
        getWindowManager().getDefaultDisplay().getMetrics(m);
        final int width = m.widthPixels/4;
        final ViewPager pager = (ViewPager)findViewById(R.id.viewpager);
        pager.setAdapter(new PagerAdapter() {
            @Override
            public int getCount() {
                return 4;
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView((View)object);
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                TextView t = new TextView(MainActivity.this);
                t.setText(position+"");
                t.setBackgroundColor(Color.BLUE);
                container.addView(t);
                return t;
            }
        });

        pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            /**
             * 从第一页滑动到第二页,positionOffset从0到1,position一直为0
             * 从第二页滑动到第一页,position为0,positionOffset从1到0
             * 也就是说position始终是屏幕左边的view
             */
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                LogUtils.e(position+"--->"+positionOffset+"--->"+positionOffsetPixels);
                if(positionOffset > 0) {
                    if(isFirst || mLastPosition != position){
                        if(positionOffset > 0.5){
                            mPreOffset = 1;
                        }else{
                            mPreOffset = 0;
                        }
                        isFirst = false;
                        mLastPosition = position;
                    }
                    cursor.setTranslationX(cursor.getTranslationX()+(positionOffset - mPreOffset) * width);
                    mPreOffset = positionOffset;
                }
            }

            @Override
            public void onPageSelected(int position) {
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                if(state == ViewPager.SCROLL_STATE_IDLE){
                    isFirst = true;
                }
            }
        });
    }
}
        使用isFirst是为了保证在每一次滑动时,只初始化一次mPreOffset。

        通过mPreOffset与positionOffset的差值,计算出本次应该移动的距离。从第一页到第二页时,mPreOffset应该为0,相反为1。

        使用mLastPosition是为了保证在极端情况下出现不正常现象。如在第二页时,开始稍微向右滑,此时mPreOffset应该是接近于0;然后往左滑,使第一页稍微出现一点,此时的positionOffset应该接近于1,这样一相减,导致了滑块在x轴上出现大幅度的移动。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值