Android-depth understanding of animation

       Android animation from use in speaking, into three categories View Animation (View movie) , also known as Tween Animation (tweens), Drawable Animation (animation frame)  , and Property Animation (animation property) . This article, I will introduce three types of animation.  

       table of Contents:

(A) View animation

(B) frame animation

(C) property animation


(A) View animation

       View animation is based on the gradual animation View, just change the rendering effect View, the actual property values View has not changed .

       View an animated object is View , which supports four kinds of animation :

  • TranslateAnimation (panning animation)
  • ScaleAnimation (zoom animation)
  • RotateAnimation (rotation animation)
  • AlphaAnimation (transparency animation)

        And provides AnimationSet animation collection. The principle is ViewGroup View every time the drawing is located in dispathDraw, the flow follows:

        

        In addition to these four typical animation, also belong essentially View animation frame animation . But the manifestation frame of the animation and the animation of these four are not the same, it is often the single carry out classified as a class.

        These four animation either through XML to define, or through the code to dynamically create.

        Before using XML we first need to create an XML file, the path is: RES / Anim / filename.xml.

1. Transparency animation

  • Code:
AlphaAnimation animation = new AlphaAnimation(0, 1);// 透明度0变化到透明度为1
animation.setDuration(1000);// 动画执行时间1s
textView.startAnimation(animation);
  • XML implementation:
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="1000"
        android:fromAlpha="0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:repeatCount="3"
        android:fillAfter="true"
        android:repeatMode="restart"
        android:toAlpha="1" />
</set>

2. rotation animation

  • Code:
RotateAnimation animation = new RotateAnimation(0, 360, 100, 100);
animation.setDuration(1000);
animation.setFillAfter(true); // 设置保持动画最后的状态
animation.setInterpolator(new AccelerateInterpolator()); // 设置插入器
textView.startAnimation(animation);

        The system also may be provided to control the animation parameters

new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  • xml achieve:
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromDegrees="0.0"
    android:interpolator="@android:anim/linear_interpolator"
    android:pivotX="50.0%"
    android:pivotY="50.0%"
    android:repeatCount="infinite"
    android:toDegrees="360.0">
</rotate>
parameter Explanation
fromDegrees Angle of rotation animation when starting this angle is zero and the current 360, is set to a different value of the angle position and then jumps to the from - to values: the negative of the forward rotation, reverse rotation canonical
toDegrees Animation rotated to an angle
pivotXType Animation object relative to the position of the X-axis type
pivotXValue Animation relative to the start position of the X coordinate of the object, this value is the original position itself as the origin, that is, as to 20% p, 20% displacement of the mobile parent control is to the right, then to the left is negative
pivotYType Animation object position relative to the Y-axis type
pivotYValue Animation start position with respect to the Y coordinate of the object, this value is itself the original position as an origin, i.e., 20% is set as P, the downward movement of the parent 20% displacement of control, the upward shift is negative

3. displacement animation

  • Code:
TranslateAnimation translateAnimation = new TranslateAnimation(0, 200, 0, 200);
translateAnimation.setDuration(1000);
textView.startAnimation(translateAnimation);
  • xml achieve:
<translate
    android:duration="1000"
    android:fillAfter="true"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:repeatCount="3"
    android:toXDelta="200"
    android:toYDelta="000">
</translate>
parameter Explanation
fromXDelta X is a movement position coordinates of the animation start
toXDelta When the end of the animation is moving on the X coordinate position
fromYDelta To move the position on the Y coordinate when the animation start
toYDelta When the end of the movement animation Y coordinate position on the

4. The zoom animation

  • Code:
ScaleAnimation animation = new ScaleAnimation(0,1,0,1);
animation.setDuration(1000);
textView.startAnimation(animation);

        Zoom animation can also set the zoom center point

ScaleAnimation animation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  • xml achieve:
<scale
    android:duration="1000"
    android:fillAfter="true"
    android:fillBefore="true"
    android:fromXScale="0.0"
    android:fromYScale="0.0"
    android:interpolator="@android:anim/linear_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="-1"
    android:repeatMode="reverse"
    android:startOffset="2000"
    android:toXScale="1.0"
    android:toYScale="1.0">
</scale>
parameter Explanation
fromX Animation is the starting X coordinate dimension of the telescopic 0.0 indicates that no shrinkage
toX When the telescopic end of the animation on the size of the X-coordinate represents the normal non-stretch 1.0
fromY Animation is the starting stretch dimension Y coordinate value means shrinkage of less than 1.0
toY Telescopic dimension value in the Y coordinate when the animation is an enlarged end is greater than 1.0
pivotXType Animation object relative to the position of the X-axis type
pivotXValue Animation relative to the start position of the X coordinate of the object
pivotXType Animation object position relative to the Y-axis type
pivotYValue Animation relative to the start position of the Y coordinate of the object

5. anim files

Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha_anim);
textView.startAnimation(animation);

6. animation collection

        AnimationSet to provide a mechanism for more than one combined into a combination of animation, the animation can be set timing relationship in the group, such as playing the same time, the order of playback.

AnimationSet animationSet = new AnimationSet(true);
animationSet.setDuration(1000);

AlphaAnimation alpha=new AlphaAnimation(0,1);
alpha.setDuration(1000);
animationSet.addAnimation(alpha);

TranslateAnimation translate = new TranslateAnimation(100, 200, 0, 200);
translate.setDuration(1000);
animationSet.addAnimation(translate);
textView.startAnimation(animationSet);

7. Animation monitor

        对于动画事件,Android也提供了开始、结束和重复事件的监听方法。

animation.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
        
    }

    @Override
    public void onAnimationEnd(Animation animation) {

    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }
});

8. View动画的特殊使用

(1)LayoutAnimation

        layoutAnimation作用于viewGroup,为ViewGroup制定一个动画,他的每个子元素都会按照这种动画出场。这种效果常被用在ListView上。使用步骤如下:

    1)定义LayoutAnimation

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"  
    android:delay="0.5" 
    android:animationOrder="reverse"  
    android:animation="@anim/animation_scale">
</layoutAnimation>

android:delay             表示子元素开始动画的时间延迟
android:animationOrder         表示子元素动画的顺序,有三个选项:

  •  normal:顺序显示
  •  reverse:表示逆向显示
  •  random:随机播放

android:animation        为子元素指定具体的入场动画

 

    2)为子元素制定具体的入场动画

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXScale="0.1"
    android:toXScale="1.5"
    android:fromYScale="0.1"
    android:toYScale="1.5"
    android:duration="2000">
</scale>

    3)为GroupView指定LayoutAnimation属性

<ListView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/xlv"
    android:layoutAnimation="@anim/animation_layout"
    android:background="#fff4f7f9"
    android:divider="#ddd"
    android:dividerHeight="1.0px"
    android:listSelector="#999">
</ListView>

 

        除了在XML文件中进行设置,我们还可以使用代码来完成: 

Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listView.setLayoutAnimation(controller);

(2)Transition Animation(过渡动画)

        Transition 也是基于属性动画的,与属性动画不同的是,它是可以实现布局改变的过渡动画。由于Transition的内容较多,具体请参照 Android Transition Framework(过渡动画框架) 

(二)帧动画

        帧动画就是加载一系列Drawable资源来创建动画,这种传统动画某种程度上就是创建不同图片序列,顺序播放,就像电影胶片。在代码中定义动画帧,使用AnimationDrawable类;XML文件能更简单的组成动画帧,在res/drawable文件夹,使用<animation-list>采用<item>来定义不同的帧。只能设置的属性是动画间隔时间。

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
   android:oneshot="false">
   <item android:drawable="@drawable/img0" android:duration="100"/>
   <item android:drawable="@drawable/img1" android:duration="100"/>
   <item android:drawable="@drawable/img2" android:duration="100"/>
   <item android:drawable="@drawable/img3" android:duration="100"/>
   <item android:drawable="@drawable/img4" android:duration="100"/>
   <item android:drawable="@drawable/img5" android:duration="100"/>
   ...
</animation-list>

        然后对组件的属性(如ImageView的android:src/android:background)直接设置即可。

ImageView iv = findViewById(R.id.image_view);
//iv.setBackgroundResource(R.drawable.drawable_animation); 
//获取背景,并将其强转成AnimationDrawable
 AnimationDrawable animationDrawable = (AnimationDrawable) iv.getBackground();
 //判断是否在运行
 if(!animationDrawable.isRunning()){
     //开启帧动画
     animationDrawable.start();
 }

        注意:帧动画的使用非常简单,但是比较容易引起OOM,所以在使用帧动画时应尽量避免使用过多尺寸较大的图片。 

(三)属性动画

        属性动画的对象除了传统的View对象,还可以是Object对象,动画之后,属性值被实实在在的改变了。因此,属性动画能够通过改变View对象的实际属性来实现View动画。任何时候View属性的改变,View能自动调用invalidate()来刷新。

        属性动画是在 Android 3.0 开始引入的新的动画形式,不过说它新只是相对的,它已经有好几年的历史了,而且现在的项目中的动画 99% 都是用的它,极少再用到 View Animation 了。属性动画不仅可以使用自带的 API 来实现最常用的动画,而且通过自定义 View 的方式来做出定制化的动画。

1. ViewPropertyAnimator

        使用方式:

        View.animate() 后跟 translationX() 等方法,动画会自动执行。

view.animate().translationX(500);

2. ObjectAnimator

        使用方式:

  • 如果是自定义控件,需要添加 setter / getter 方法;
  • 用 ObjectAnimator.ofXXX() 创建 ObjectAnimator 对象;
  • 用 start() 方法执行动画。
public class SportsView extends View {

    float progress = 0;
    
    ......
    
    // 创建 getter 方法
    public float getProgress() {
        return progress;
    }

    // 创建 setter 方法
    public void setProgress(float progress) {
        this.progress = progress;
        invalidate();
    }
    
    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        
        ......
        
        canvas.drawArc(arcRectF, 135, progress * 2.7f, false, paint);
        
        ......
    }
}

......

// 创建 ObjectAnimator 对象
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "progress", 0, 65);
// 执行动画
animator.start();

3. 通用功能

(1)setDuration(int duration) 设置动画时长

(2)setInterpolator(Interpolator interpolator) 设置 Interpolator(插值器)

  • AccelerateDecelerateInterpolator  先加速再减速  (默认的 Interpolator)
  • LinearInterpolator  匀速
  • AccelerateInterpolator  持续加速
  • DecelerateInterpolator  持续减速直到 0
  • AnticipateInterpolator  先回拉一下再进行正常动画轨迹
  • OvershootInterpolator  动画会超过目标值一些,然后再弹回来
  • AnticipateOvershootInterpolator  上面这两个的结合版:开始前回拉,最后超过一些然后回弹
  • BounceInterpolator  在目标值处弹跳
  • CycleInterpolator  这个也是一个正弦 / 余弦曲线
  • FastOutLinearInInterpolator  用贝塞尔曲线持续加速
  • LinearOutSlowInInterpolator  持续减速,初始速度更高
  • PathInterpolator  自定义动画完成度 / 时间完成度曲线
Path interpolatorPath = new Path();

...

// 匀速
interpolatorPath.lineTo(1, 1);

(3)setListener() / ObjectAnimator.addListener()  设置监听器

        参数类型是 AnimatorListener,所以本质上其实都是一样的。 AnimatorListener共有 4 个回调方法

  • onAnimationStart(Animator animation)
  • onAnimationEnd(Animator animation)
  • onAnimationCancel(Animator animation)
  • onAnimationRepeat(Animator animation)

补充:setUpdateListener() /addUpdateListener()

        和上面两个方法类似,但是这两个方法虽然名称和可设置的监听器数量不一样,但本质其实都一样的。它们的参数都是 AnimatorUpdateListener。它只有一个回调方法:

  • onAnimationUpdate(ValueAnimator animation)

4. TypeEvaluator

        关于 ObjectAnimator,可以用 ofInt() 来做整数的属性动画和用 ofFloat() 来做小数的属性动画。这两种属性类型是属性动画最常用的两种,不过在实际的开发中,可以做属性动画的类型还是有其他的一些类型。当需要对其他类型来做属性动画的时候,就需要用到 TypeEvaluator 了。

(1)ArgbEvaluator

   TypeEvaluator 最经典的用法是使用 ArgbEvaluator 来做颜色渐变的动画。

ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xffff0000, 0xff00ff00);
animator.setEvaluator(new ArgbEvaluator());
animator.start();

        在 Android 5.0 (API 21) 加入了新的方法 ofArgb()。

ObjectAnimator animator = ObjectAnimator.ofArgb(view, "color", 0xffff0000, 0xff00ff00);
animator.start();

(2)自定义 Evaluator

// 自定义 HslEvaluator
private class HsvEvaluator implements TypeEvaluator<Integer> {
   float[] startHsv = new float[3];
   float[] endHsv = new float[3];
   float[] outHsv = new float[3];

   @Override
   public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
       // 把 ARGB 转换成 HSV
       Color.colorToHSV(startValue, startHsv);
       Color.colorToHSV(endValue, endHsv);

       // 计算当前动画完成度(fraction)所对应的颜色值
       if (endHsv[0] - startHsv[0] > 180) {
           endHsv[0] -= 360;
       } else if (endHsv[0] - startHsv[0] < -180) {
           endHsv[0] += 360;
       }
       outHsv[0] = startHsv[0] + (endHsv[0] - startHsv[0]) * fraction;
       if (outHsv[0] > 360) {
           outHsv[0] -= 360;
       } else if (outHsv[0] < 0) {
           outHsv[0] += 360;
       }
       outHsv[1] = startHsv[1] + (endHsv[1] - startHsv[1]) * fraction;
       outHsv[2] = startHsv[2] + (endHsv[2] - startHsv[2]) * fraction;

       // 计算当前动画完成度(fraction)所对应的透明度
       int alpha = startValue >> 24 + (int) ((endValue >> 24 - startValue >> 24) * fraction);

       // 把 HSV 转换回 ARGB 返回
       return Color.HSVToColor(alpha, outHsv);
   }
}

ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xff00ff00);
// 使用自定义的 HslEvaluator
animator.setEvaluator(new HsvEvaluator());
animator.start();

(3)使用不限定类型的属性做动画

        借助于 TypeEvaluator,属性动画就可以通过 ofObject() 来对不限定类型的属性做动画了。

    1)为目标属性写一个自定义的 TypeEvaluator

    2)使用 ofObject() 来创建 Animator,并把自定义的 TypeEvaluator 作为参数填入

private class PointFEvaluator implements TypeEvaluator<PointF> {
   PointF newPoint = new PointF();

   @Override
   public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
       float x = startValue.x + (fraction * (endValue.x - startValue.x));
       float y = startValue.y + (fraction * (endValue.y - startValue.y));

       newPoint.set(x, y);

       return newPoint;
   }
}

ObjectAnimator animator = ObjectAnimator.ofObject(view, "position",
        new PointFEvaluator(), new PointF(0, 0), new PointF(1, 1));
animator.start();

5. PropertyValuesHolder

        很多时候,我们需要在同一个动画中改变多个属性,例如在改变透明度的同时改变尺寸。如果使用 ViewPropertyAnimator,你可以直接用连写的方式来在一个动画中同时改变多个属性。

view.animate()
        .scaleX(1)
        .scaleY(1)
        .alpha(1);

        而对于 ObjectAnimator,是不能这么用的。不过你可以使用 PropertyValuesHolder 来同时在一个动画中改变多个属性。

PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1);
 
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3)
animator.start();

6. AnimatorSet 

        有的时候,我们不止需要在一个动画中改变多个属性,还会需要多个动画配合工作,比如,在内容的大小从 0 放大到 100% 大小后开始移动。这种情况使用 PropertyValuesHolder 是不行的,因为这些属性如果放在同一个动画中,需要共享动画的开始时间、结束时间、Interpolator 等一系列的设定,这样就不能有先后次序地执行动画了。这就需要用到 AnimatorSet 了。

ObjectAnimator animator1 = ObjectAnimator.ofFloat(...);
animator1.setInterpolator(new LinearInterpolator());
ObjectAnimator animator2 = ObjectAnimator.ofInt(...);
animator2.setInterpolator(new DecelerateInterpolator());
 
AnimatorSet animatorSet = new AnimatorSet();
// 两个动画依次执行
animatorSet.playSequentially(animator1, animator2);
animatorSet.start();

  AnimatorSet 还可以这么用:

// 两个动画同时执行
animatorSet.playTogether(animator1, animator2);
animatorSet.start();

        以及这么用:

// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)
// 的方式来精确配置各个 Animator 之间的关系
animatorSet.play(animator1).with(animator2);
animatorSet.play(animator1).before(animator2);
animatorSet.play(animator1).after(animator2);
animatorSet.start();

7. PropertyValuesHolders.ofKeyframe() 

        除了合并多个属性和调配多个动画,你还可以在 PropertyValuesHolder 的基础上更进一步,通过设置 Keyframe (关键帧),把同一个动画属性拆分成多个阶段。例如,你可以让一个进度增加到 100% 后再「反弹」回来。

// 在 0% 处开始
Keyframe keyframe1 = Keyframe.ofFloat(0, 0);
// 时间经过 50% 的时候,动画完成度 100%
Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);
// 时间见过 100% 的时候,动画完成度倒退到 80%,即反弹 20%
Keyframe keyframe3 = Keyframe.ofFloat(1, 80);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);
animator.start();

 

总结:「关于复杂的属性关系来做动画」,就这么三种:

  1. 使用 PropertyValuesHolder 来对多个属性同时做动画;
  2. 使用 AnimatorSet 来同时管理调配多个动画;
  3. PropertyValuesHolder 的进阶使用:使用 PropertyValuesHolder.ofKeyframe() 来把一个属性拆分成多段,执行更加精细的属性动画。
发布了37 篇原创文章 · 获赞 38 · 访问量 1万+

Guess you like

Origin blog.csdn.net/qq_34519487/article/details/104078222