您的浏览器不支持CSS3,建议使用Firfox、Chrome等浏览器,以取得最佳显示效果

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

Android 477℃ 0 1年前 (2016-06-03)

示例代码、思维导图可在此下载
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" />
  1. Animation anim = AnimationUtils.loadAnimation(this, R.anim.animation);
  2. mTextView.startAnimation(anim);
  1. 常用XML定义动画,用Java代码加载,并设置给View

  2. 也可以在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>
  1. // 返回的是AnimationSet实例,AnimationSet继承自Animation
  2. Animation anim = AnimationUtils.loadAnimation(this, R.anim.animation_set);
  3. mTextView.startAnimation(anim);
  1. startOffset:默认set中所有动画是同时播放的,如果有设置startOffset,那一项就会延时播放。这样就可以实现一系列的动画效果了。

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

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

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

  5. 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. }
  1. initialize方法中,对坐标尺寸相关内容进行初始化

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

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

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

  5. 也可以在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. }
  1. 自定义Interpolator,需要实现Interpolator接口的getInterpolation方法。这个方法相当于一个数学函数,输入值、输出值范围都是0~1。

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

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

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

  3. 上面的代码中,将整个动画播放过程进行了分段,每段加速或者减速,最后配合自定义的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);
来自为知笔记(Wiz)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

0

暂无评论

评论前:需填写以下信息,或 登录

用户登录

忘记密码?