巧妙运用补间动画,自定义广告轮播CarouselView 2.0

  这是前一篇文章绘制的CarouselView的升级版,有兴趣的同学,可以去关注一下笔者前一篇文章。自定义广告图片轮播View——CarouselView

这次升级版相对于前文而已,有了一个功能上的飞跃主要区别体现如下:

  1. 构建方式更简单
  2. 提供更多的API拱用户自定义
  3. 提供5中不同应用场景的动画

  本文除了提供源码和API外,还会详细讲解如何利用补间动画以及ViewPager.PageTransformer实现花样轮播控件。如果对补间动画还存在疑惑的同学可以阅读笔者的另外一篇文章弥补一下。这次彻底搞懂Android补间动画

先看效果:

饿,不知道为什么,这里做成gif后异常的卡顿,实际效果肯定是如丝版顺滑的。


ANIM_ALPHA_PAGETRANS.gif
ANIM_LEFTLEAVE.gif
ANIM_ROTATEMAGIC.gif
ANIM_SCALEMAGIC.gif
ANIM_SCALERIGHTLEAVE.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预留出显示的地方,然后设置viewpagerpagermargin,目的是将3个Item分开,item与item之间留有空白。最后也是最关键的为fragmeLayoutveiwPager设置属性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:

PageTransformer的postion

  我们可以看到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.
      }
}

拿两个动画来举个例子:

  1. ANIM_SCALEMAGIC:


    ANIM_SCALEMAGIC.gif

这个动画是非常实用的,我们看动画可以总结一下几点:

  1. 一个页面需要显示多个Item
  2. 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));
            }
        }
    }
  1. 我们设置两个常量,默认在左右边的渐变和缩放大小分别为50%和90%

  2. 设置(-infinite,-1)和(1,infinite) 的状态,即在左右两遍时,view十倍缩小了并且透明了

  3. 设置[-1,0)的状态,当postion=-1时,我们需要ScaleX=0.9f,postion=0时,ScaleX=1.0f。很显然,这只是一个二元一次方程,可得ScaleX=1+.01f*position。

  4. 设置(0,1]的状态,同上方式,我们可以计算出ScaleX=1-0.1f*position。

  5. 到此我们已经完成了Scale动画的绘制,然后是Aplha动画,从[-1,1]Item是一个从透明到不透明再到透明的过程,笔者采用了代码中的算法,其实可以同设置Scale动画一样,逐步设置。

  6. ANIM_SCALERIGHTLEAVE:


    ANIM_SCALERIGHTLEAVE.gif

首先先总结一下这个动画的要点:

  1. 传统的轮播方式,同一页只显示一个Item
  2. 滑动时包含一个缩放动画
  3. 缩小时包含一个渐变动画
  1. 设置两个缩放和渐变的最小渐变值分别为0.85f和0.5f
  2. (-infinity,-1)(-,infinity)设置为全透明,因为一个页面值显示Item,所以为了方便,直接可以设置全透明
  3. (-1,1)分别设置位移动画、缩放动画以及渐变动画

源码:

wusyLibrary://wusylibrary/src/main/java/com/wusy/wusylibrary/view/CarouselView.java
扫描文章末尾的二维码,关注笔者的公众号:饮水思源|wusy,回复Android源码获取。感谢你的支持。

End

笔者的Github Blog,希望各位大大提意见,点个star,谢谢
传送门:WusyBlog

求互粉互赞,互赞所有文章可以私聊我。哈哈,希望我们的原创文章能让更多朋友看到,一起变强。

笔者新开通了微信公众号——饮水思源|wusy 计划持续运营,每日为您分享Android干货、原创文章。微信扫描下方的二维码关注我,开发学习路上不迷路。谢谢各位


饮水思源|wusy.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容