Android Animation完全总结(二)Animation动画与LayoutAnimation

示例代码、思维导图可在此下载
https://github.com/jzj1993/AndroidAnimation

Animation(补间动画 / Tween Animation)

Animation通过对View的显示矩阵进行变换,实现了整个View的动画效果。Android提供的几种Animation,都有完整的XML支持,使用简单方便,功能较为全面。

Android提供的Animation包括:

  • RotateAnimation,旋转动画
  • TranslateAnimation,平移动画
  • ScaleAnimation,缩放动画
  • AlphaAnimation,透明度动画

下面是旋转动画示例:

res/anim/animation.xml

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <rotate xmlns:android="http://schemas.android.com/apk/res/android"

  3. android:duration="1000"

  4. android:fromDegrees="0"

  5. android:interpolator="@android:interpolator/linear"

  6. android:pivotX="50%"

  7. android:pivotY="50%"

  8. android:repeatCount="infinite"

  9. android:repeatMode="restart"

  10. android:toDegrees="360" />

  11. Animation anim = AnimationUtils.loadAnimation(this, R.anim.animation);

  12. mTextView.startAnimation(anim);

  13. 常用XML定义动画,用Java代码加载,并设置给View

  14. 也可以在Java代码中创建,参考工程源码

属性相关

  • from-to属性:动画起始、终止的位置(或角度、透明度等)

  • duration 动画持续时间,单位是ms

  • pivotX, pivotY 指定旋转的中心点。pivotX="50%"50%表示元素自身尺寸的50%, 50%p表示父元素尺寸的50%

    注意:这里指定的中心点坐标是相对坐标原点而言的,而坐标原点在View的左上角。

    假设想让View沿着父视图的中心旋转,由于坐标原点在View左上角,而不是父视图左上角,所以写成50%p是不能正常工作的(除非两者左上角重合)。可以在Java代码中进行计算。

  • repeatMode : reverse 反转; restart 重新开始

  • repeatCount : 5 循环五次;infinite 无限循环

Interpolator 插值器

用于控制动画播放速度,Android系统提供的常用Interpolator有:

  • LinearInterpolator 匀速线性动画
  • AccelerateInterpolator 加速动画
  • DecelerateInterpolator 减速动画
  • AccelerateDecelerateInterpolator,先加速再减速
  • BounceInterpolator,弹跳形式

AnimationSet

AnimationSet继承自Animation,用于实现多个Animation叠加的效果。通常也在XML中定义。

res/anim/animation_set.xml

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <set xmlns:android="http://schemas.android.com/apk/res/android"

  3. android:duration="2000"

  4. android:fillAfter="true">

  5. <translate

  6. android:fromXDelta="0"

  7. android:fromYDelta="-50%p"

  8. android:interpolator="@android:interpolator/accelerate_decelerate"

  9. android:toXDelta="0"

  10. android:toYDelta="0" />

  11. <alpha

  12. android:fromAlpha="0.5"

  13. android:startOffset="2000"

  14. android:toAlpha="1" />

  15. <scale

  16. android:fromXScale="1"

  17. android:fromYScale="1"

  18. android:pivotX="50%"

  19. android:pivotY="50%"

  20. android:startOffset="4000"

  21. android:toXScale="2"

  22. android:toYScale="2" />

  23. </set>

  24. // 返回的是AnimationSet实例,AnimationSet继承自Animation

  25. Animation anim = AnimationUtils.loadAnimation(this, R.anim.animation_set);

  26. mTextView.startAnimation(anim);

  27. startOffset:默认set中所有动画是同时播放的,如果有设置startOffset,那一项就会延时播放。这样就可以实现一系列的动画效果了。

  28. fillAfter:设置为true时,动画播放完成后停留在最后一帧,而不是复位到初始位置

  29. android:fromYDelta="-50%p" 坐标原点还是左上角,但由于TranslateAnimation是平移运动,这里就可以直接用这种方式实现从父视图的上方中心位置开始移动。

  30. 注意:android:fromAlpha="0.5" 虽然Alpha动画在2s时才开始执行,但是在0s的时候,View的Alpha值就已经被设置成fromAlpha的数值了。类似的,如果设置了Scale的初始值不为1,整个View的坐标比例也会发生变化。例如初始Scale为0.5,则50%p实际上只有父视图的25%。

  31. AnimationSet继承自Animation,但它继承的一些属性比较特别。其中的一些属性,会直接被设置给它包含的每个Animation;而另外一些属性会被忽略;还有一些属性会被应用到AnimationSet本身。可参考AnimationSet中的JavaDoc:

    • duration, repeatMode, fillBefore, fillAfter: These properties, when set on an AnimationSet object, will be pushed down to all child animations.
    • repeatCount, fillEnabled: These properties are ignored for AnimationSet.
    • startOffset, shareInterpolator: These properties apply to the AnimationSet itself.

使用Java代码实例化Animation

  1. Animation anim = new TranslateAnimation(
  2. Animation.RELATIVE_TO_PARENT, -0.2f, Animation.RELATIVE_TO_PARENT, -0.2f,
  3. Animation.RELATIVE_TO_PARENT, -0.5f, Animation.RELATIVE_TO_PARENT, 0
  4. );
  5. anim.setFillAfter(true);
  6. anim.setDuration(2000);
  7. mTextView.setAnimation(anim);

CustomAnimation CustomIntepolator

自定义Animation

  1. public class MyAnimation extends Animation {

  2. private float mFromXValue = 0.0f;

  3. private float mFromYValue = 0.0f;

  4. private float mFromXDelta;

  5. private float mFromYDelta;

  6. public MyAnimation(float fromXDelta, float fromYDelta) {

  7. mFromXValue = fromXDelta;

  8. mFromYValue = fromYDelta;

  9. }

  10. @Override

  11. public void initialize(int width, int height, int parentWidth, int parentHeight) {

  12. super.initialize(width, height, parentWidth, parentHeight);

  13. mFromXDelta = parentWidth * mFromXValue;

  14. mFromYDelta = parentHeight * mFromYValue;

  15. }

  16. /**

  17. * @param interpolatedTime 0~1f

  18. * @param t

  19. */

  20. @Override

  21. protected void applyTransformation(float interpolatedTime, Transformation t) {

  22. float dx = mFromXDelta + ((0 - mFromXDelta) * interpolatedTime);

  23. float dy = mFromYDelta + ((0 - mFromYDelta) * interpolatedTime);

  24. final Matrix matrix = t.getMatrix();

  25. // pre-方法向前生长,post-方法向后生长,set-方法先清空已有变换,再进行变换

  26. matrix.setTranslate(dx, dy);

  27. }

  28. }

  29. initialize方法中,对坐标尺寸相关内容进行初始化

  30. applyTransformation方法中,对矩阵Matrix进行变换实现动画

    • interpolatedTime参数取值为0~1f,代表当前动画执行到的位置。
  31. matrix.setTranslate(dx, dy)matrix.postRotate(180)matrix.preScale(scaleX, scaleY)。post-方法向后生长(在先调用变换的基础上在做后调用的变换),pre-方法向前生长,set-方法先清空已有变换,再进行变换。如果要进行多个变换,最多使用一个set方法。

  32. 上面的代码实现了一个类似TranslateAnimation的自定义动画。

  33. 也可以在applyTransformation中执行其他操作,而不是调用Matrix的相关方法变换View。例如设置View的LayoutParam,实现View宽高的渐变动画;设置View的Margin,实现View在其Parent中位置的平移。

自定义Interpolator

  1. public class MyInterpolator implements Interpolator {

  2. float[] rawStep; // 1f, 0.5f, 0.5f, 0.25f, 0.25f, 0.125f, 0.125f, ...

  3. float[] normalizedStep; // 1k, 0.5k, 0.5k, ...

  4. float[] normalizedStepSum; // 0, 1k, (1+0.5)k, (1+0.5+0.5)k, ..., 1

  5. float sum;

  6. public MyInterpolator() {

  7. final int k = 10;

  8. rawStep = new float[2 * k + 1];

  9. normalizedStep = new float[rawStep.length];

  10. normalizedStepSum = new float[rawStep.length + 1];

  11. rawStep[0] = 1f;

  12. float f = 1f;

  13. for (int i = 0; i < k; ++i) {

  14. rawStep[2 * i] = f;

  15. rawStep[2 * i + 1] = f;

  16. f /= 2f;

  17. }

  18. sum = 0;

  19. for (float f1 : rawStep) {

  20. sum += f1;

  21. }

  22. normalizedStepSum[0] = 0;

  23. for (int i = 0; i < rawStep.length; ++i) {

  24. normalizedStep[i] = rawStep[i] / sum;

  25. normalizedStepSum[i + 1] = normalizedStepSum[i] + normalizedStep[i];

  26. }

  27. }

  28. public float getInterpolation(float input) {

  29. float r = 1;

  30. for (int i = 0; i < normalizedStep.length; ++i) {

  31. if (input < normalizedStepSum[i + 1]) {

  32. float x = (input - normalizedStepSum[i]) / normalizedStep[i]; // x = 0~1

  33. if (i % 2 == 0) { // down

  34. return accelerate(x, r);

  35. } else { // up

  36. return decelerate(x, r);

  37. }

  38. }

  39. if (i % 2 == 0) {

  40. r /= 2;

  41. }

  42. }

  43. return input;

  44. }

  45. /**

  46. * @param x

  47. * @param range

  48. * @return 1-range ~ 1

  49. */

  50. float accelerate(float x, float range) {

  51. return x * x * range + 1 - range;

  52. }

  53. /**

  54. * @param x

  55. * @param range

  56. * @return 1-range ~ 1

  57. */

  58. float decelerate(float x, float range) {

  59. return (1 - x) * (1 - x) * range + 1 - range;

  60. }

  61. }

  62. 自定义Interpolator,需要实现Interpolator接口的getInterpolation方法。这个方法相当于一个数学函数,输入值、输出值范围都是0~1。

  63. 动画播放的时候,每刷新一帧就会调用一次getInterpolation方法,输入的参数从0到1线性递增;而返回值作为interpolatedTime参数传入到Animation的applyTransformation方法中。

    • LinearInterpolator的getInterpolation方法是一次函数,返回值等于输入值,所以返回值也会线性递增。

    • AccelerateInterpolator,则是对输入值求N次方(例如平方),所以就会有加速的效果。

  64. 上面的代码中,将整个动画播放过程进行了分段,每段加速或者减速,最后配合自定义的TranslateAnimation,实现了View下落弹跳的效果。实际效果参考工程源码。

AnimationListener 监听器

  1. Animation anim = new MyAnimation(0f, -0.5f);

  2. anim.setInterpolator(new MyInterpolator());

  3. anim.setDuration(8000);

  4. anim.setFillAfter(true);

  5. anim.setAnimationListener(new Animation.AnimationListener() {

  6. @Override

  7. public void onAnimationStart(Animation animation) {

  8. mTextView.setText("Animation");

  9. }

  10. @Override

  11. public void onAnimationEnd(Animation animation) {

  12. mTextView.setText("Hello World");

  13. }

  14. @Override

  15. public void onAnimationRepeat(Animation animation) {

  16. }

  17. });

  18. mTextView.startAnimation(anim);

LayoutAnimation,用于ViewGroup

XML方式实现

定义每个ChildView的动画

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <set xmlns:android="http://schemas.android.com/apk/res/android"

  3. android:duration="500">

  4. <scale

  5. android:fromXScale="0"

  6. android:fromYScale="0"

  7. android:pivotX="50%"

  8. android:pivotY="50%"

  9. android:toXScale="1"

  10. android:toYScale="1" />

  11. <alpha

  12. android:fromAlpha="0"

  13. android:toAlpha="1" />

  14. </set>

定义LayoutAnimation

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:animation="@anim/layout_animation_item"
  4. android:animationOrder="normal"
  5. android:delay="0.15" />

在ViewGroup中应用LayoutAnimation

  1. <LinearLayout android:layoutAnimation="@anim/layout_animation" >
  2. </LinearLayout>

ViewGroup加载时,按照animationOrder属性指定的顺序(顺序、倒序、随机),delay属性指定的时延,让每个ChildView依次显示动画。

Java创建LayoutAnimation

  1. Animation anim = AnimationUtils.loadAnimation(this, R.anim.layout_animation_item);

  2. LayoutAnimationController lac = new LayoutAnimationController(anim);

  3. lac.setOrder(LayoutAnimationController.ORDER_REVERSE);

  4. lac.setDelay(1);

  5. mListView.setLayoutAnimation(lac);