前言
按照掘金惯例,先放些小姐姐的图,不然你们没性趣往下看了
思路
通过集成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,喜欢的给个星吧!