android中的动画实现方式繁多,在项目中也经常用到动画,网上有很多人也都进行了一些总结,但是感觉还是零零散散,自己总结一下才能加深印象,以后有时间了,也可以从各个分类里进一步去补充完善。



文章目录

  • 一、View Animation
  • 1、Tween Animation 补间动画
  • 2、Frame Animation(Drawable Animation)逐帧动画
  • 二、Property Animation 属性动画
  • 1、ValueAnimator
  • 2、ValueAnimator
  • 三、Spring Animation 弹性动画
  • 四、Fling Animation
  • 五、 Layout Animation 布局动画
  • 六、 Layout Transition 布局转场动画
  • 七、 Activity transition Activity转场动画
  • 1、使用transition启动一个Activity
  • 2、shared element共享元素动画
  • 八、用ConstraintLayout和ConstraintSet实现动画
  • 九、用MotionLayout实现动画


一、View Animation

1、Tween Animation 补间动画

  这类动画比较简单,一般就是平移、缩放、旋转、透明度,或者其组合,可以用代码或者xml文件的形式,推荐使用xml文件形式,因为可以复用。

TranslateAnimation、ScaleAnimation、RotateAnimation、AlphaAnimation、AnimationSet,对应的的XML标签为translate、 scale、 rotate、alpha、set,其中set里还可以放set,然后放在放置在res/anim/目录下,关于详细使用这里不再做介绍。

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

代码中使用:

ImageView image = (ImageView) findViewById(R.id.image);
Animation hyperspaceJump = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
image.startAnimation(hyperspaceJump);
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.animator.property_animator);
set.setTarget(myObject);
set.start();

参考网上的一个停止补间动画的正确姿势:

public void stopAnimation(View v) {
    v.clearAnimation();
    if (canCancelAnimation()) {
       v.animate().cancel();    
    }    
    animation.setAnimationListener(null);    
    v.setAnimation(null);
}

/**
 * Returns true if the API level supports canceling existing animations via the 
 * ViewPropertyAnimator, and false if it does not 
 * @return true if the API level supports canceling existing animations via the 
 * ViewPropertyAnimator, and false if it does not 
 */
public static boolean canCancelAnimation() {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
}

2、Frame Animation(Drawable Animation)逐帧动画

  如果要做很炫酷的下来刷新或者loading动画,可以考虑使用Airbnb开源的动画框架Lottie   简单讲就是把几个静态的图片快速播放形成动画,可以使用AnimationDrawable,官方推荐使用XML文件,放在res/drawable/路径下,
代码如下所示:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/thrust1" android:duration="200" />
    <item android:drawable="@drawable/thrust2" android:duration="200" />
    <item android:drawable="@drawable/thrust3" android:duration="200" />
</animation-list>

  android:oneshot="true"表示只执行一次动画,false表示无限循环,

ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketImage.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        rocketAnimation.start();
      }
  });

  注意调用AnimationDrawable的start方法时,不能在Activity的onCreat里,因为这时AnimationDrawable还没有完全依附到window上,如果一开始就想执行动画,可以放在onStart方法里

矢量动画AnimatedVectorDrawable, 感兴趣的可以查看这里
https://developer.android.google.cn/guide/topics/graphics/drawable-animation

二、Property Animation 属性动画

  属性动画,顾名思义,只要对象里有属性的set和get方法,就可以利用这个属性去做动画。
  上面介绍的View Animation都是对View进行的操作,准确的说,是改变View的绘制,并没有改变View对象本身的属性值,且只有一些基本的动画效果,不能改变background color等,属性动画可以对任何对象进行改变(我好像还没遇到这种场景)。官网介绍,相比Property Animation,View Animation启动所需的时间少,要写的代码也少,所以,如果能用视图动画搞定的动画,就没有必要使用属性动画了。

  在android.view.animation包里定义的差值器interpolators可以用在属性动画中。

  属性动画使用Animator的子类,通常是ValueAnimator和ObjectAnimator ,ValueAnimator只能计算属性值的变化,可以设置监听然后自己处理相关逻辑;ObjectAnimator可以对对象的属性值计算后,直接应用于对象的相应属性。

1、ValueAnimator

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();

  或者对自定义的类型进行动画:

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}
fadeAnim.start();

animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

2、ValueAnimator

  ObjectAnimator和AnimatorSet的使用:

ObjectAnimator.ofFloat(targetObject, "propName", 1f)

AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

  在一次需要修改多个属性值时,除了可以使用AnimatorSet, 还可以使用语法更简洁的ViewPropertyAnimator,同时ViewPropertyAnimator也更高效,代码对比如下:

Multiple ObjectAnimator objects

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

One ObjectAnimator

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

ViewPropertyAnimator

myView.animate().x(50f).y(100f);

  关于ViewPropertyAnimator的更多介绍,可以查看官网介绍 blog post.

三、Spring Animation 弹性动画

  这类动画是模仿现实中的弹力效果,每一帧都是通过计算相应的弹力=得到,可以设置弹性动画的阻尼率和刚度来达到不同的弹性效果。

添加依赖

dependencies {
      implementation 'com.android.support:support-dynamic-animation:27.1.1'
  }

以下是一个应用了链式弹性动画Chained spring的效果图,

Android popwindow 动画 android动画效果大全_android

SpringAnimation类,具体可参考官网介绍:Animate movement using spring physics 或者 Android中弹簧动画的那些事 - SpringAnimation

四、Fling Animation

  Fling Animation类似于列表ListView在快速滚动时到最后列表停止滚动的效果。

Android popwindow 动画 android动画效果大全_属性动画_02

FlingAnimation类,具体可参考官网介绍:Move views using a fling animation

五、 Layout Animation 布局动画

  当改变一个布局的元素时,android提供了一种预加载动画,使用默认的布局动画,只需要对一个layout设置一个属性,如下所示:

<LinearLayout android:id="@+id/container"
    android:animateLayoutChanges="true"
    ...
/>

当对这个LinearLayout中添加、删除或者更新子View时,这些子View就会自动添加上默认的动画效果。

private ViewGroup mContainerView;
...
private void addItem() {
    View newView;
    ...
    mContainerView.addView(newView, 0);
}

除了默认的布局动画,也可以自定义动画,并使用setAnimator方法设置给ViewGroup,以后有时间可以仔细研究一下,

public void setAnimator (int transitionType, 
                Animator animator)

六、 Layout Transition 布局转场动画

  转场动画可以在两个布局之间,产生动画效果,步骤如下:

  1.根据其实布局和结束布局,创建Scene对象,
  2.创建一个Transition对象,用来定义所需的动画类型
  3.调用TransitionManager.go(),然后系统就在两个布局之间产生动画

Android popwindow 动画 android动画效果大全_android_03

  更多内容请参考 Animate layout changes using a transition
Create a custom transition animation

七、 Activity transition Activity转场动画

  从Android5.0(API21)开始,可以使用 Activity transition,所以要注意低版本的效果适配。

1、使用transition启动一个Activity

  当给一个Activity指定了退出的转场动画,在启动一个新的Activity时,将调用动画效果,如果新启动的Activity也设置了进入的转场动画,那么在启动时,也会产生相应的动画,要禁用动画效果时,传一个空的bundle

  使用Activity转场动画,要在使用的theme里,将android:windowActivityTransitions设置为true

<style name="BaseAppTheme" parent="android:Theme.Material">
  <!-- enable window content transitions -->
  <item name="android:windowActivityTransitions">true</item>

  <!-- specify enter and exit transitions -->
  <item name="android:windowEnterTransition">@transition/explode</item>
  <item name="android:windowExitTransition">@transition/explode</item>

  <!-- specify shared element transitions -->
  <item name="android:windowSharedElementEnterTransition">
    @transition/change_image_transform</item>
  <item name="android:windowSharedElementExitTransition">
    @transition/change_image_transform</item>
</style>

  然后在代码中

// inside your activity (if you did not enable transitions in your theme)
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

// set an exit transition
getWindow().setExitTransition(new Explode());

startActivity(intent,
              ActivityOptions.makeSceneTransitionAnimation(this).toBundle());

2、shared element共享元素动画

  可以共享一个或者多个元素,简要代码如下,

// get the element that receives the click event
final View imgContainerView = findViewById(R.id.img_container);

// get the common element for the transition in this activity
final View androidRobotView = findViewById(R.id.image_small);

// define a click listener
imgContainerView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent(this, Activity2.class);
        // create the transition animation - the images in the layouts
        // of both activities are defined with android:transitionName="robot"
        ActivityOptions options = ActivityOptions
            .makeSceneTransitionAnimation(this, androidRobotView, "robot");
        // start the new activity
        startActivity(intent, options.toBundle());
    }
});

  多个共享元素时:

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
        Pair.create(view1, "agreedName1"),
        Pair.create(view2, "agreedName2"));


八、用ConstraintLayout和ConstraintSet实现动画

  这个放在最后写,因为感觉最牛逼啊,其实和上面介绍到的Layout Transition 布局转场动画很相似,先是用ConstraintLayout写两个布局文件,然后利用TransitionManager调用beginDel ayedTransition()启动一个延时转场动画就行,且ConstraintLayout支持到API 9,TransitionManager支持到API 14,所以多使用ConstraintSet来做动画,兼容性不用担心,除了在两个布局里转场,在一个布局内改变某个View的属性(如边距),其余的View也会自动产生平滑的动画效果,其他什么动画相关代码都不用写,,,,,惊不惊喜!

  利用给Transition设置相应的差值器Interpolator,就能产生更加fashion的效果,感兴趣的同学可以观看以下视频教程:



九、用MotionLayout实现动画

MotionLayout 因何而生?
Android 框架已经提供了好几种在 App 里添加动画的方式:

Animated Vector Drawable
Property Animation framework
LayoutTransition animations
Layout transitions with TransitionManager
CoordinatorLayout

下面将揭示 MotionLayout 和上面这些已有方案的不同。