旋转木马效果的ViewPager

前言

按照掘金惯例,先放些小姐姐的图,不然你们没性趣往下看了


思路

通过集成ViewPager的形式实现,先看代码

public class CarouselViewPager extends ViewPager {
    public CarouselViewPager(Context context) {
        super(context);
        setChildrenDrawingOrderEnabled(true);
    }
    public CarouselViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setChildrenDrawingOrderEnabled(true);
    }
    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        int currentItem = getCurrentItem();
        if (i >= currentItem) {
            return childCount - 1 - i + currentItem;
        }
        return super.getChildDrawingOrder(childCount, i);
    }
}复制代码

其实很简单主要重写了getChildDrawingOrder()方法,关于这个方法官方说明如下:

* Returns the index of the child to draw for this iteration. Override this
* if you want to change the drawing order of children. By default, it
* returns i.复制代码

就是说返回的是子view的绘制顺序,如果你希望改变绘制的顺序就重写他,默认返回的是子View 在ViewGroup中的索引,所以我们在addView()的时候,后面的会在最上面。这里我们重写的目的就是当前选中的View在最上面,我们先来看下不重写上面的方法的效果图:


可以看到后面的view把前面的盖住了。注意,setChildrenDrawingOrderEnabled(true);否则即使重写了getChildDrawingOrder()也没有用,在ViewPager在setPageTransformer()中,如图,


做了判断,所以此处可以省略,最好加上吧!接下来看下CarouselTransformer,这个是控制切换过度动画的,比较简单:


public class CarouselTransformer implements ViewPager.PageTransformer {
    public static final float SCALE_MIN = 0.3f;
    public static final float SCALE_MAX = 1f;
    public float scale;

    private float pagerMargin;
    private float spaceValue;

    public CarouselTransformer(@FloatRange(from = 0,to = 1) float scale, float pagerMargin, float spaceValue) {
        this.scale = scale;
        this.pagerMargin = pagerMargin;
        this.spaceValue = spaceValue;
    }

    @Override
    public void transformPage(View page, float position) {

        if (scale != 0f) {
            float realScale = getAdapter(1 - Math.abs(position * scale), SCALE_MIN, SCALE_MAX);
            page.setScaleX(realScale);
            page.setScaleY(realScale);
        }

        if (pagerMargin != 0) {

            float realPagerMargin = position * (pagerMargin);
            page.setTranslationX(realPagerMargin);
        }
    }

    private float getAdapter(float value, float minValue, float maxValue) {
        return Math.min(maxValue, Math.max(minValue, value));
    }

}
复制代码

复制代码

通过page.setScaleX(realScale); page.setScaleY(realScale);实现缩放,通过 page.setTranslationX(realPagerMargin);实现层叠遮罩效果。

值得注意的是,在Viewpager的父View中,加了这一句: android:clipChildren="false"

clipChildren表示是否限制子View在其范围内, 默认情况下,clipChild为true。 也就是不允许子View在超出父View的范围进行绘制,这个时候Viewpager只会显示当前的Item,达不到上述的效果。我们将其值设置为false后,当子控件的高度高于父控件时也会完全显示。另外在MainActivity中有个小优化:

frameLayout.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return mViewCard.dispatchTouchEvent(event);
    }
});复制代码

为了将滑动事件交给ViewPage处理,否则的话如果滑动的不是当前选中的Item,没有效果,体验不好。

后记

代码github,喜欢的给个星吧!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值