导言

作为一个开发安卓app的程序员,常常需求在app界面作出各式各样的动画作用,所以如何让咱们开发的动画作用尽可能的靠近产品给出的需求(样例)是一件蛮根底但又很重要的作业,接下来,我会经过一个构思示例来展示这一开发进程,期望经过这个构思示例共享开发安卓动画作用的实践经验,激起读者的构思思想,并期待读者提出宝贵的定见和建议。

预备开发动画作用的前期作业

其实,最重要的也便是这一步,咱们拿到了需求,看了要求与作用样例后,榜首件事不该该是急匆匆的写代码,当然,假如需求很简单直接写代码也不妨,所以在这达成一认知后,咱们来看看本文的示例是否能够直接写代码(其实也是根据作者自身对动画作用的组合运用不是很娴熟这一状况来的,假如开发时刻长一些,许多需求仍是能够直接上手写代码了)。

首要,咱们看看需求,这儿有作用示意图:

安卓动画组合拳:创意示例带您掌握动画效果开发技巧

这一看就知道一定是一段动画作用组合而成,除非是个切图做成Lottie的GIF。

拿到需求后,咱们需求剖析一下作用的完成进程,也便是拆分完成进程:

  1. 需求两个图标,且放置方位不同
  2. 点击下面音讯款式图标(以下简称“音讯”)的右上角“删去”图标(以下简称“删去”)时分,删去会消失
  3. 删去消失的一起,音讯也会迅速边移动到铃铛图标(以下简称“铃铛”)方位边缩小直到消失
  4. 音讯消失时铃铛开端闪烁一下接着摇摆几下

以上便是将一整个功能拆分的进程,这样做的好处便是能够更快的写出适宜的代码,也便是将所谓的动画组合拳(最终的动画作用)进行招式拆分,逐渐学习了解,最终才干融会贯通,构成一套行云流水。

进入正式开发作业

前面进行了拆分,那就需求为这些拆分好的进程找到适宜的动画作用办法代码,为其“点睛”。

首要榜首步,咱们需求把布局整理好,即做好对应未呈现动画时的UI界面:
代码如下:
XML布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/vAlarm"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_gravity="end"
        android:layout_marginEnd="64dp"
        android:layout_marginTop="16dp"
        app:srcCompat="@drawable/vector_alarm_test"/>
    <LinearLayout
        android:id="@+id/vLlMessageButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end"
        android:layout_marginEnd="16dp"
        android:layout_marginTop="500dp"
        android:orientation="vertical">
        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/vMessageButtonClose"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_gravity="end"
            app:srcCompat="@drawable/vector_alarm_delete_test"/>
        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/vMessageButtonImage"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_gravity="end"
            android:layout_marginEnd="16dp"
            android:layout_marginTop="10dp"
            app:srcCompat="@drawable/vector_alarm_message_test"/>
    </LinearLayout>
</LinearLayout>

安卓动画组合拳:创意示例带您掌握动画效果开发技巧
首要咱们选用LinearLayout线性布局,在当中放入三张图进行布局,组合出对应的界面作用,其间三个要害的view是vAlarm,vLlMessageButton,与vMessageButtonClose,咱们在代码中为其添加事情和动画作用。

Activity代码:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatImageView vMessageButtonClose = findViewById(R.id.vMessageButtonClose);
        vMessageButtonClose.post(new Runnable() {
            @Override
            public void run() {
                clickMessageButtonCloseAnimation();
            }
        });
    }
}

咱们在Activity中的onCreate()办法中添加了vMessageButtonClose这个view的post办法,并在post里边的Runnable方针里调用了咱们的动画完成事情函数clickMessageButtonCloseAnimation(),这样做的好处便是这个函数履行时咱们的UI元素已经被制作出来了,一些测量的数据不会呈现变成0的状况。

咱们的clickMessageButtonCloseAnimation()函数内容(MyTest/app/src/main/java/com/example/mytest/MainActivity.java at main ObliviateOnline/MyTest GitHub,内容比较长,就不直接附在此处了,能够到作者Github这个地址看看)便是本篇的重点。这个函数内容很杂乱,由于我将动画作用主体完成进程都放到这个办法里边了,所以咱们下面就从各方面逐渐解析它。

安卓动画作用常识根底

在解析这段函数的代码前咱们要看看安卓中写添加动画作用要运用哪些常识。

一补间动画和特点动画的不同

安卓中首要有两种完成动画的办法,分别是补间动画和特点动画,粗略的说,补间动画比较简单,是经过改动View的特点值,并生成一系列中间状况来完成动画作用;而特点动画就杂乱一些,经过改动Object的特点值,并生成一系列中间状况来完成动画作用。

除此以外,经过一些材料上说的,补间动画的兼容性没那么好,也没特点动画完成的流通,总之便是特点动画有点各方面碾压补间动画的意思。

二补间动画的完成办法

咱们在安卓中能够经过Animation类及其子类首要用于完成补间动画,其原理是经过改动View的特点值,从初始状况到最终状况的进程中,逐渐地生成一系列中间状况,让View在这些中间状况之间滑润过渡,然后构成动画作用。

咱们常用的有如下几种Animation类子类:

  1. RotateAnimation:是Android中用于完成旋转动画作用的一个子类,它能够让一个View或Drawable方针沿着中心点或指定轴线进行旋转。
  2. ScaleAnimation:用于完成缩放动画作用,能够让一个View或Drawable方针沿着中心点或指定轴线进行扩大或缩小。
  3. TranslateAnimation:用于完成平移动画作用,能够让一个View或Drawable方针沿着指定的轴线进行平移。
  4. AlphaAnimation:用于完成透明度动画作用,能够让一个View或Drawable方针的透明度进行突变。 示例:
// 获取需求旋转的View方针
View view = findViewById(R.id.myView);
// 创立RotateAnimation方针
RotateAnimation animation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
// 设置动画特点
animation.setDuration(1000); // 持续时刻为1秒
animation.setRepeatCount(Animation.INFINITE); // 无限循环
// 发动动画
view.startAnimation(animation);

三特点动画的完成办法

在安卓中一般经过Animator类完成特点动画,比方AnimatorSet和ObjectAnimator的运用。与补间动画不同,特点动画会经过滑润过渡来完成动画作用,显得更加天然和流通。

AnimatorSet是一个用于组合多个动画作用的类,它能够一起播映、次序播映、并行播映多个特点动画,一般便是用来组合咱们需求的动画作用。

而ObjectAnimator能够改动指定方针的指定特点值,并生成一系列中间状况,经过滑润过渡来完成动画作用。例如,能够经过ObjectAnimator来完成View的平移、旋转、缩放等动画作用,也能够经过ObjectAnimator来完成自定义特点的动画作用,例如背景色彩、字体大小等,这是用来具体完成作用的。
示例:
就和本篇的例子相同,咱们能够经过运用AnimatorSet来组合多个ObjectAnimator然后完成杂乱的动画作用

// 获取需求动画的View方针
View view = findViewById(R.id.myView);
// 创立ObjectAnimator方针
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 1.5f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 1.5f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(view, "rotation", 0f, 360f);
// 创立AnimatorSet方针
AnimatorSet animatorSet = new AnimatorSet();
// 设置动画特点
animatorSet.play(scaleX).with(scaleY).before(rotate);
animatorSet.setDuration(1000); // 持续时刻为1秒
animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); // 加速度和减速度插值器
// 发动动画
animatorSet.start();

以上便是咱们需求提前了解的常识,其实只需好用或者方便,运用哪种都行,混合着用也没啥,只需最终作用能完美完成就行,并且这些类的完成也不是必定对应着特点动画和补间动画的,一些完成特点动画的类也能够去完成补间动画。

了解完了根底的常识部分,下面就开端正式剖析,这儿不从代码次序去解析,由于这个次序其实不是代码逻辑次序,咱们是从事情触发次序来叙述:

事情一:vMessageButtonClose按钮点击事情

首要咱们先看最终几行代码,这儿是咱们在点击删去按钮时分事情触发的代码,咱们在点击时将这个删去按钮隐藏并发动相应动画事情。

这也就对应了这几行代码:

 // 按钮点击事情
    vMessageButtonClose.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            vMessageButtonClose.setVisibility(View.GONE);
            // 发动动画
            animatorSet.start();
        }
    });

,animatorSet.start()也表明咱们选用的是特点动画,这儿考虑的是让动画全体更流通,由于咱们的动画是组合而成,相对仍是比较杂乱的,运用特点动画虽然费事可是最终作用更好。

事情二:动画组合事情注册

咱们在上一个事情中有发动动画这行代码,其间animatorSet方针需求先去创立好相应活动进程:

// 创立 AnimatorSet,将两个动画组合起来
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(firstAnimatorSet).before(secondScaleAnimatorX).before(secondScaleAnimatorY);

这段代码就在事情一上面,这是创立AnimatorSet方针来组合后边需求的动画的,让动画依照咱们想要的次序来履行,上面代码动画履行次序是:
firstAnimatorSet–>secondScaleAnimatorXsecondScaleAnimatorY

before()办法实际上是设置了动画之间的依赖关系,指定了一个动画(play)在另一个动画(before)履行之前播映,也便是在play()办法之后履行。

事情三:分进程写动画作用

这一块内容多一些,也是最首要的部分,动画作用的完成,这儿还要分红两部分firstAnimatorSet动画 与secondScaleAnimatorXsecondScaleAnimatorY动画

firstAnimatorSet动画完成

首要咱们来看最费事的部分,这一步便是咱们看到最主体的动画作用,也便是点击删去按钮后音讯移动到铃铛的进程,这儿能够再细分为位移与缩放。

位移

位移是需求咱们进行计算的,也便是如下代码:

 // 获取当前方位的 View 中心点坐标
    int[] startLocation = new int[2];
    vLlMessageButton.getLocationOnScreen(startLocation);
    float startX = startLocation[0] +vLlMessageButton.getWidth() / 2f;
    float startY = startLocation[1] + vLlMessageButton.getHeight() / 2f;
    // 获取方针方位的 View 中心点坐标,并考虑到缩放因子
    int[] endLocation = new int[2];
    vAlarm.getLocationOnScreen(endLocation);
    float endX = endLocation[0] + vAlarm.getWidth() * sc;
    float endY = endLocation[1] + vAlarm.getHeight() * sc / 2f;
    // 计算需求移动的距离
    float deltaX = endX - startX;
    float deltaY = endY - startY;
    // 创立榜首个动画,将 View 移动到方针方位并一起进行缩放
    ObjectAnimator moveAnimatorX = ObjectAnimator.ofFloat(vLlMessageButton, "translationX", 0f, deltaX);
    ObjectAnimator moveAnimatorY = ObjectAnimator.ofFloat(vLlMessageButton, "translationY", 0f, deltaY);

这儿最重要的是要考虑到咱们两个图标大小由于不相同,位移进程需求缩放对位移坐标发生的影响,很简单移动偏了,不是简单的获取一下两个view组件的自身坐标就行的。

在计算好位移距离后,咱们选用ObjectAnimator方针的translationX和translationY记载xy坐标的移动动画moveAnimatorXmoveAnimatorY,这样,咱们的位移就做好了,接下来写缩放和组合小动画。

缩放和拼接动画

这块仍是比较简单了,代码如下:

ObjectAnimator scaleAnimatorX = ObjectAnimator.ofFloat(vLlMessageButton, "scaleX", sc);
    ObjectAnimator scaleAnimatorY = ObjectAnimator.ofFloat(vLlMessageButton, "scaleY", sc);
    AnimatorSet firstAnimatorSet = new AnimatorSet();
    firstAnimatorSet.playTogether(moveAnimatorX, moveAnimatorY, scaleAnimatorX, scaleAnimatorY);
    firstAnimatorSet.setDuration(500);
    firstAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator());

咱们这儿运用scaleX和scaleY缩放动画再创立两个ObjectAnimator方针,一起咱们用AnimatorSet(firstAnimatorSet)去拼接这些小的动画作用进程,运用playTogether()办法去让这些动画进程一起进行,运用AccelerateDecelerateInterpolator插值器(setInterpolator)以及设置对应动画时刻(setDuration)去完成咱们的榜首部分动画作用。

接着咱们还得在榜首部分动画作用中加点东西,让另一个View组件铃铛也要有动画作用,然后与前面音讯的动画作用衔接起来,由于firstAnimatorSet方针中咱们能够监听其开端和完毕等活动,所以咱们需求在这个方针的动画完毕监听里添加一个新的动画作用(针对铃铛的缩放以及后续的摇摆动画),代码如下:

//监听动画完毕,设置alarm图标缩放动画
    firstAnimatorSet.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
        }
        @Override
        public void onAnimationEnd(Animator animation) {
            //与此一起,alarm图标动画开端: 1.缩小到消失(和悬浮图标同步)2.再次显现,alarm图标进行摇摆
            Animation scale = new ScaleAnimation(1f, 0, 1f, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            scale.setDuration(100);
            AnimationSet animSet = new AnimationSet(true);
            animSet.addAnimation(scale);
            vAlarm.startAnimation(animSet);
            animSet.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }
                @Override
                public void onAnimationEnd(Animation animation) {
                    vLlMessageButton.setVisibility(View.GONE);
                    //alarm图标动画: 1.缩小到消失(和悬浮图标同步)2.再次显现,alarm图标进行摇摆
                    Animation shake = new RotateAnimation(-3, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0f);
                    shake.setInterpolator(new CycleInterpolator(3));
                    shake.setDuration(1000);
                    vAlarm.startAnimation(shake);
                }
                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
        }
        @Override
        public void onAnimationCancel(Animator animation) {
        }
        @Override
        public void onAnimationRepeat(Animator animation) {
        }
    });

这块代码有点套娃的感觉,由于自身便是在音讯图标的动画方针中监听的,结果创立新的动画方针(铃铛图标缩放)后最终又创立一个新的(铃铛图标摇摆),所以总共三层了,可是了解也很简单,作用便是: 榜首部分动画作用完毕(音讯位移到铃铛),铃铛动画开端:1.缩小到消失(和音讯图标同步)2.再次显现 ,铃铛缩放动画完毕,铃铛摇摆动画进行。

这儿的缩放和上面的创立不是相同的,这儿咱们选用了补间动画,咱们创立的Animation方针的子方针ScaleAnimation用来缩放,后边摇铃也是子类方针RotateAnimation用来操控旋转来起到摇摆的作用(还利用到查找器CycleInterpolator来完成周期动画作用的),当然,这其间的参数都要根据需求的实际作用来设置,时刻也要对应精确,不然作用会显得很突兀,这方面只需经过常常练习才干比较好掌握其间的度。

到这儿,咱们最杂乱的动画部分完毕了,下面是音讯图标的二次缩放。

音讯图标的二次缩放动画

这儿要说的便是secondScaleAnimatorXsecondScaleAnimatorY动画,用来操控音讯图标位移到铃铛方位后缩小到消失这段动画进程的,其实时刻上正好和之前说的铃铛缩放动画同步,这儿是经过设置对应长度的动画时刻来确定的,不是什么神奇的技巧。

这一部分很简单,咱们先看看代码:

  // 创立第二个动画,将 View 缩放至 0
    ObjectAnimator secondScaleAnimatorX = ObjectAnimator.ofFloat(vLlMessageButton, "scaleX", 0f);
    ObjectAnimator secondScaleAnimatorY = ObjectAnimator.ofFloat(vLlMessageButton, "scaleY", 0f);
    secondScaleAnimatorX.setDuration(100);
    secondScaleAnimatorY.setDuration(100);
    secondScaleAnimatorX.setInterpolator(new AccelerateDecelerateInterpolator());
    secondScaleAnimatorY.setInterpolator(new AccelerateDecelerateInterpolator());

便是ObjectAnimator创立两个缩放动画即可,然后咱们再用相同的参数去设置这两个动画以保持一致,以避免缩放的xy坐标比例不协调。

这样咱们的全体动画作用就完成了,作用便是文章开端的作用图,首要的要求便是要能够正确的拆分好动画的每一步然后给组合好,其实也必定有其他的组合办法,这不是仅有的。

结语

这儿仅仅是敞开进程的一例,当然还会有更加费事的动画作用组合,可是假如能依照这种办法顺次去拆分好每一步,再去一一组合起来,其实仍是非常简单的,最多不过是代码的长度添加了而已,期望这个例子能对读者有所启发,也欢迎掘友们指正!