这是前一篇文章绘制的CarouselView的升级版,有兴趣的同学,可以去关注一下笔者前一篇文章。自定义广告图片轮播View——CarouselView
这次升级版相对于前文而已,有了一个功能上的飞跃主要区别体现如下:
- 构建方式更简单
- 提供更多的API拱用户自定义
- 提供5中不同应用场景的动画
本文除了提供源码和API外,还会详细讲解如何利用补间动画以及ViewPager.PageTransformer实现花样轮播控件。如果对补间动画还存在疑惑的同学可以阅读笔者的另外一篇文章弥补一下。这次彻底搞懂Android补间动画
先看效果:
饿,不知道为什么,这里做成gif后异常的卡顿,实际效果肯定是如丝版顺滑的。
CarouselView 2.0 如何使用:
ArrayList<CarouselView.CarouselBean> beans=new ArrayList<>();
beans.add(new CarouselView.CarouselBean(R.mipmap.img1,"第一张图"));
beans.add(new CarouselView.CarouselBean(R.mipmap.img2));
beans.add(new CarouselView.CarouselBean(R.mipmap.img3,"第三张图"));
beans.add(new CarouselView.CarouselBean(R.mipmap.img4,"第四张图"));
beans.add(new CarouselView.CarouselBean(R.mipmap.img5,"第五张图"));
beans.add(new CarouselView.CarouselBean(R.mipmap.img6));
carouselView.init(beans,CarouselView.ANIM_LEFTLEAVE);
可见,使用方式还是非常简单的,简单的bean文件,支持传入图片和图片描述(可选),然后调用init方法初始化即可,第二个参数是动画,动画也是选传项,不设置动画则显示传统的轮播控件。
已经封装好5个动画提供给使用者使用。动画支持自定义。
在写文过程中,笔者发现,2.0页不是那么完善,比如没有提供网络图片的显示API,没有对外提供动画自定义的支持等等,这些内容笔者会考虑在3.0里提供,如果收到反馈和留言的话!!
CarouselView API:
void init(ArrayList<CarouselBean> beans,int anim)
: 控件初始化方法
参数一(必填):beans是图片的集合,包含图片和图片描述 。
参数二(选填):anim是动画参数,控件已封装了5个动画,对应5个常量,以ANIM开头。
void setIsRunningCarousel(boolean isRunning)
:控制轮播是否开启,默认为false,即不开启
void setIntervalsTime(int intervalsTime)
:控制轮播间隔时间,默认为5000ms
void setBottomViewBackGroundColor(int colorResource)
:设置底部描述文字布局的背景颜色,推荐#6000
void setPointVisible(boolean visible)
设置是否显示底部指示器,默认为true,即显示
public void setDescVisible(boolean visible)
:是否显示文字描述,默认为false,即不显示
关于轮播动画:
从上面的效果图中,我们可以看到,实现的动画可以分为两大类。
第一类是只显示一个Item的动画,这类动画和传统的轮播没什么大的差异,只是多了一些补间动画修饰。
第二类是一页显示多个Item的动画,这样的轮播图看着更时尚也更高端,相比较于第一类,只是多了这样一段代码:
/**
* 当需要ViewPager一个界面显示多个Item的时候,调用改方法。
*/
private void excisionPage(){
FrameLayout.LayoutParams lp=new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(120,40,120,40);
viewPager.setLayoutParams(lp);
viewPager.setClipChildren(false);
frameLayout.setClipChildren(false);
//设置Page间间距
viewPager.setPageMargin(20);
//设置缓存的页面数量
if(beans.size()>5)viewPager.setOffscreenPageLimit(2);
}
上图中的viewpager
是包裹在frameLayout
里面的,我们给frameLayout
添加margins
,目的是给两遍的Item预留出显示的地方,然后设置viewpager
的pagermargin
,目的是将3个Item分开,item与item之间留有空白。最后也是最关键的为fragmeLayout
和veiwPager
设置属性setClipChildren(false)
,该属性能够让Android不去自动裁剪超出布局的部分,也就是我们ViewPager
左右两遍的Item正常情况下是会被裁剪掉,不显示的,而设置该属性为false
后能保证他们存活。
添加动画:
既然要添加动画,首先我们肯定需要拿到在滑动的时候的一个可变化的值。ViewPager为我们提供了这样一个借口,我们实现VeiwPager.PageTransformer借口,然后添加进我们的ViewPager即可
private void initAnim(int anim) {
switch (anim){
case ANIM_ALPHA_PAGETRANS:
excisionPage();
viewPager.setPageTransformer(true,new AlphaPageTransformer());
break;
case ANIM_SCALEMAGIC:
excisionPage();
viewPager.setPageTransformer(true,new ScaleMagic());
break;
case ANIM_ROTATEMAGIC:
excisionPage();
viewPager.setPageTransformer(true,new RotateMagic());
break;
case ANIM_LEFTLEAVE:
viewPager.setPageTransformer(true,new LeftLeave());
break;
case ANIM_SCALERIGHTLEAVE:
viewPager.setPageTransformer(true,new ScaleRightLeave());
break;
case ANIM_NORMAL:
default:
viewPager.setClipChildren(true);
frameLayout.setClipChildren(true);
break;
}
}
/**
* 当需要ViewPager一个界面显示多个Item的时候,调用改方法。
*/
private void excisionPage(){
FrameLayout.LayoutParams lp=new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(120,40,120,40);
viewPager.setLayoutParams(lp);
viewPager.setClipChildren(false);
frameLayout.setClipChildren(false);
//设置Page间间距
viewPager.setPageMargin(20);
//设置缓存的页面数量
if(beans.size()>5)viewPager.setOffscreenPageLimit(2);
}
如何自定义ViewPager的PageTransformer:
我们可以看到
void transformPage(View view, float position)
的position
的值主要需要关注得是position=-1、position=0、postion=1
三个状态,当ViewPager的Item处于正中间时,他的postion=1
。从而我们只要确定3个点的状态,然后添加补间动画让他动起来的就可以了,不过我们也需要绘制在
position<-1,postion>1
的状态,否则在未滑动的时候,会空白。综上所述,我们代码可以这样写:
@Override
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
} else if (position <= 0) { // [-1,0]
} else if (position <= 1) { // (0,1]
} else { // (1,+Infinity]
// This page is way off-screen to the right.
}
}
拿两个动画来举个例子:
-
ANIM_SCALEMAGIC:
这个动画是非常实用的,我们看动画可以总结一下几点:
- 一个页面需要显示多个Item
- position=-1时(在左边时),是被缩小了的,有一个Scale动画,还有一个Alpha的渐变动画。postion=1(右边)时,同postion=-1;
有了上述总结,我们直接上代码:
private class ScaleMagic implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.90f;
private static final float MIN_ALPHA = 0.5f;
@Override
public void transformPage(View page, float position) {
if (position < -1 || position > 1) {
page.setAlpha(MIN_ALPHA);
page.setScaleX(MIN_SCALE);
page.setScaleY(MIN_SCALE);
} else if (position <= 1) { // [-1,1]
if (position < 0) {
float scaleX = 1 + 0.1f * position;
page.setScaleX(scaleX);
page.setScaleY(scaleX);
} else {
float scaleX = 1 - 0.1f * position;
page.setScaleX(scaleX);
page.setScaleY(scaleX);
}
float scaleFactor = Math.max(MIN_ALPHA, 1 - Math.abs(position));
page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_ALPHA) / (1 - MIN_ALPHA) * (1 - MIN_ALPHA));
}
}
}
我们设置两个常量,默认在左右边的渐变和缩放大小分别为50%和90%
设置(-infinite,-1)和(1,infinite) 的状态,即在左右两遍时,view十倍缩小了并且透明了
设置[-1,0)的状态,当postion=-1时,我们需要ScaleX=0.9f,postion=0时,ScaleX=1.0f。很显然,这只是一个二元一次方程,可得ScaleX=1+.01f*position。
设置(0,1]的状态,同上方式,我们可以计算出ScaleX=1-0.1f*position。
到此我们已经完成了Scale动画的绘制,然后是Aplha动画,从[-1,1]Item是一个从透明到不透明再到透明的过程,笔者采用了代码中的算法,其实可以同设置Scale动画一样,逐步设置。
-
ANIM_SCALERIGHTLEAVE:
首先先总结一下这个动画的要点:
- 传统的轮播方式,同一页只显示一个Item
- 滑动时包含一个缩放动画
- 缩小时包含一个渐变动画
- 设置两个缩放和渐变的最小渐变值分别为0.85f和0.5f
- (-infinity,-1)(-,infinity)设置为全透明,因为一个页面值显示Item,所以为了方便,直接可以设置全透明
- (-1,1)分别设置位移动画、缩放动画以及渐变动画
源码:
wusyLibrary://wusylibrary/src/main/java/com/wusy/wusylibrary/view/CarouselView.java
扫描文章末尾的二维码,关注笔者的公众号:饮水思源|wusy,回复Android源码
获取。感谢你的支持。
End
笔者的Github Blog,希望各位大大提意见,点个star,谢谢
传送门:WusyBlog求互粉互赞,互赞所有文章可以私聊我。哈哈,希望我们的原创文章能让更多朋友看到,一起变强。
笔者新开通了微信公众号——饮水思源|wusy 计划持续运营,每日为您分享Android干货、原创文章。微信扫描下方的二维码关注我,开发学习路上不迷路。谢谢各位