Android项目总结(3)-登陆页图片循环过渡播放动画效果

这是项目总结第三篇,前两篇分别为:java

1. Android 项目总结(1)- 之弧形ViewPager 和弧形HeaderViewandroid

2 . Android项目总结(二)时间、数字选择器和省市区三级联动ide

今天为你们分享一个简单的登陆背景动画,图片循环播放动画,具体效果是啥样子的呢?先上一张效果图: 动画

login_alpha

login_alpha2.gif

1、需求

咱们开发APP的时候,通常都有一个注册登陆的入口页面,这个页面的呈现有不少种方式,如:spa

  • 静态背景图 + 注册登陆按钮
  • 视频背景 + 注册登陆按钮
  • 背景动画 + 注册登陆按钮

今天分享的就是第三种 ,背景动画,效果图如上所示,接下来就分析一下这个动画:code

1 . 有 N 张图片切换(项目中用的4张) 2 . 图片切换过渡:当前图片放大而且淡出,下一张显示的图片淡入。 3 . 图片循环播放,显示到最后一张时又从第一张开始。cdn

2、实现

上面对照效果图分析了动画的几个点,那么接下来就看怎么实现,咱们选择用属性动画来实现,具体实现思路以下:视频

本例中有4张图片:A,B,C,D 有4组动画: A->B B->C C->D D->Axml

这样4组就实现了循环切换图片

而后就是每一组动画的实现,其实很简单,一个Scale 放大效果+ 一个 alpha 效果:

A -> B:

ObjectAnimator animator1 = ObjectAnimator.ofFloat(mBgView1, "alpha", 1.0f, 0f);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(mBgView2, "alpha", 0f, 1.0f);
        ObjectAnimator animatorScale1 = ObjectAnimator.ofFloat(mBgView1, "scaleX", 1.0f, 1.3f);
        ObjectAnimator animatorScale2 = ObjectAnimator.ofFloat(mBgView1, "scaleY", 1.0f, 1.3f);
        AnimatorSet animatorSet1 = new AnimatorSet();
        animatorSet1.setDuration(5000);
        animatorSet1.play(animator1).with(animator2).with(animatorScale1).with(animatorScale2);
复制代码

B->C:

ObjectAnimator animator3 = ObjectAnimator.ofFloat(mBgView2, "alpha", 1.0f, 0f);
        ObjectAnimator animator4 = ObjectAnimator.ofFloat(mBgView3, "alpha", 0f, 1.0f);
        ObjectAnimator animatorScale3 = ObjectAnimator.ofFloat(mBgView2, "scaleX", 1.0f, 1.3f);
        ObjectAnimator animatorScale4 = ObjectAnimator.ofFloat(mBgView2, "scaleY", 1.0f, 1.3f);
        AnimatorSet animatorSet2 = new AnimatorSet();
        animatorSet2.setDuration(5000);
        animatorSet2.play(animator3).with(animator4).with(animatorScale3).with(animatorScale4);
复制代码

C->D:

ObjectAnimator animator5 = ObjectAnimator.ofFloat(mBgView3, "alpha", 1.0f, 0f);
        ObjectAnimator animator6 = ObjectAnimator.ofFloat(mBgView4, "alpha", 0f, 1.0f);
        ObjectAnimator animatorScale5 = ObjectAnimator.ofFloat(mBgView3, "scaleX", 1.0f, 1.3f);
        ObjectAnimator animatorScale6 = ObjectAnimator.ofFloat(mBgView3, "scaleY", 1.0f, 1.3f);
        AnimatorSet animatorSet3 = new AnimatorSet();
        animatorSet3.setDuration(5000);   
        animatorSet3.play(animator5).with(animator6).with(animatorScale5).with(animatorScale6);
复制代码

D->A:

ObjectAnimator animator7 = ObjectAnimator.ofFloat(mBgView4, "alpha", 1.0f, 0f);
        ObjectAnimator animator8 = ObjectAnimator.ofFloat(mBgView1, "alpha", 0f, 1.0f);
        ObjectAnimator animatorScale7 = ObjectAnimator.ofFloat(mBgView4, "scaleX", 1.0f, 1.3f);
        ObjectAnimator animatorScale8 = ObjectAnimator.ofFloat(mBgView4, "scaleY", 1.0f, 1.3f);
        AnimatorSet animatorSet4 = new AnimatorSet();
        animatorSet4.setDuration(5000);
        animatorSet4.play(animator7).with(animator8).with(animatorScale7).with(animatorScale8);
复制代码

上面的代码展现了每一组动画,将每组动画中的几个动画放在一个AnimatorSet 中,设置为同时播放。最后咱们须要将这4组动画按照顺序连接起来,怎么连接呢?用AnimatorSetplaySequentially方法。以下:

AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playSequentially(animatorSet1, animatorSet2, animatorSet3, animatorSet4);
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                // 这个是实现循环播放的关键
                animation.start();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animatorSet.start();
复制代码

其中有一个关键点:在监听动画结束的回调方法中,调用animation.start(); 实现循环播放。

你觉得到此这篇文章就结束了吗? 固然尚未,上面的代码其实效果已经出来了,可是仍是有点问题?什么问题呢?就是当播放完第一次,后面循环播放的时候会有一个跳动。 为何呢? 看看上面的代码就会发现,当执播放完一轮后,4张图片都放大了 1.3 倍数。

ObjectAnimator animatorScale1 = ObjectAnimator.ofFloat(mBgView1, "scaleX", 1.0f, 1.3f);
ObjectAnimator animatorScale2 = ObjectAnimator.ofFloat(mBgView1, "scaleY", 1.0f, 1.3f);
复制代码

而后重复播放的时候,又会执行scale 动画,从 1.0 -> 1.3 ,所以实际上会先从 1.3 -> 1.0。再执行缩放动画,这就是跳动的缘由,所以在播放完一轮后,咱们要将放大的View 先复位到原大小,而后在执行动画。在onAnimationEnd 方法中复位。

最终代码以下:

ObjectAnimator animator1 = ObjectAnimator.ofFloat(mBgView1, "alpha", 1.0f, 0f);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(mBgView2, "alpha", 0f, 1.0f);
        ObjectAnimator animatorScale1 = ObjectAnimator.ofFloat(mBgView1, "scaleX", 1.0f, 1.3f);
        ObjectAnimator animatorScale2 = ObjectAnimator.ofFloat(mBgView1, "scaleY", 1.0f, 1.3f);
        AnimatorSet animatorSet1 = new AnimatorSet();
        animatorSet1.setDuration(5000);
        animatorSet1.play(animator1).with(animator2).with(animatorScale1).with(animatorScale2);


        ObjectAnimator animator3 = ObjectAnimator.ofFloat(mBgView2, "alpha", 1.0f, 0f);
        ObjectAnimator animator4 = ObjectAnimator.ofFloat(mBgView3, "alpha", 0f, 1.0f);
        ObjectAnimator animatorScale3 = ObjectAnimator.ofFloat(mBgView2, "scaleX", 1.0f, 1.3f);
        ObjectAnimator animatorScale4 = ObjectAnimator.ofFloat(mBgView2, "scaleY", 1.0f, 1.3f);
        AnimatorSet animatorSet2 = new AnimatorSet();
        animatorSet2.setDuration(5000);
        animatorSet2.play(animator3).with(animator4).with(animatorScale3).with(animatorScale4);


        ObjectAnimator animator5 = ObjectAnimator.ofFloat(mBgView3, "alpha", 1.0f, 0f);
        ObjectAnimator animator6 = ObjectAnimator.ofFloat(mBgView4, "alpha", 0f, 1.0f);
        ObjectAnimator animatorScale5 = ObjectAnimator.ofFloat(mBgView3, "scaleX", 1.0f, 1.3f);
        ObjectAnimator animatorScale6 = ObjectAnimator.ofFloat(mBgView3, "scaleY", 1.0f, 1.3f);
        AnimatorSet animatorSet3 = new AnimatorSet();
        animatorSet3.setDuration(5000);
        animatorSet3.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                // 放大的View复位
                mBgView1.setScaleX(1.0f);
                mBgView1.setScaleY(1.0f);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animatorSet3.play(animator5).with(animator6).with(animatorScale5).with(animatorScale6);


        ObjectAnimator animator7 = ObjectAnimator.ofFloat(mBgView4, "alpha", 1.0f, 0f);
        ObjectAnimator animator8 = ObjectAnimator.ofFloat(mBgView1, "alpha", 0f, 1.0f);
        ObjectAnimator animatorScale7 = ObjectAnimator.ofFloat(mBgView4, "scaleX", 1.0f, 1.3f);
        ObjectAnimator animatorScale8 = ObjectAnimator.ofFloat(mBgView4, "scaleY", 1.0f, 1.3f);
        AnimatorSet animatorSet4 = new AnimatorSet();
        animatorSet4.setDuration(5000);
        animatorSet4.play(animator7).with(animator8).with(animatorScale7).with(animatorScale8);


        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playSequentially(animatorSet1, animatorSet2, animatorSet3, animatorSet4);
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                // 将放大的View 复位
                mBgView2.setScaleX(1.0f);
                mBgView2.setScaleY(1.0f);
                mBgView3.setScaleX(1.0f);
                mBgView3.setScaleY(1.0f);
                mBgView4.setScaleX(1.0f);
                mBgView4.setScaleY(1.0f);
                // 循环播放
                animation.start();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animatorSet.start();

复制代码

xml代码:

<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:id="@+id/login_bg_image4"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/login_bg4" />

        <ImageView
            android:id="@+id/login_bg_image3"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/login_bg3" />

        <ImageView
            android:id="@+id/login_bg_image2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/login_bg2" />

        <ImageView
            android:id="@+id/login_bg_image1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/login_bg1" />
    </FrameLayout>
复制代码

注意ImageView的顺序,第一张图应该在最上面。

注意: 四个View复位的地方不同,第一个是在第二组动画执行完毕后复位的,为何没有和其余几个一块儿放到最后呢? 由于 D -> A 的时候就须要显示A,这个时候这一轮是没有播放完的,所以D->A 的时候会跳动。因此咱们把他放到前面复位。

3、总结

很简单的一个循环过渡动画,本文是用属性动画实现的。固然确定还有其余实现方式,如:放一个gif图或者帧动画也是能够的,可是这样可能就须要切不少张图,增长了咱们apk 的体积。其余方法你们能够去探索一下,欢迎交流。

相关文章
相关标签/搜索