Android动画

作者: 咸鱼佬 | 来源:发表于2017-05-11 11:17 被阅读133次

Android 动画大致可以分为view animation(视图动画,补间动画) ,drawable animation(帧动画),property animation(属性动画)

View Animation

视图动画只能作用于view对象,是对view的变换,有以下的四种变换

  1. AlphaAnimation(透明度变化)
  2. ScaleAnimation(缩放变化)
  3. TranslateAnimation(位移变化)
  4. RotateAnimation (旋转变化)

还有一个AnimationSet让上面的动画集合起来一起运行,都是Animation的子类

AlphaAnimation

直接alpha作为根元素

<?xml version="1.0" encoding="utf-8"?>
<alpha
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fillAfter="true"
    android:fromAlpha="0.0"
    android:toAlpha="1.0"
    >
</alpha>

或者用set作为根元素

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="2000"
        android:fillAfter="true"
        android:fromAlpha="0.0"
        android:toAlpha="1.0"
        />
</set>

将xml加载到view中

alphaImageView.startAnimation(AnimationUtils.loadAnimation(MainActivity.this,R.anim.alpha));

再或者可以直接用java new 一个AlphaAnimation出来

AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f, 1.0f);
alphaAnimation.setDuration(1000);//必须设置一个大于0的数值,默认是0
alphaImageView.startAnimation(alphaAnimation);

运行的gif就不放了,用到的属性说明下,

  • toAlpha 动画结束时的透明度 float (0.0 ~ 1.0,完全透明~完全不透明)
  • fromAlpha 动画开始的透明度 float
  • duration 动画持续时间 单位毫秒
  • fillAfter 动画结束后是否保持结束后的状态 boolean true为保持

ScaleAnimation

参数介绍 :

  • fromX 动画开始时X轴的缩放比例,1.0表示当前view的正常比例
  • toX 动画结束时x轴的缩放比例,那么在x轴缩放的比例就是 toX - fromX
  • fromY 类似
  • toY 类似
  • pivotX x方向上的缩放起点,默认是0
  • pivotY Y方向上的缩放起点,默认是0
  • pivotType 缩放起点的类型,有三种
    /**
     * The specified dimension is an absolute number of pixels.
     * 默认是这种,相对于控件的0坐标
     */
    public static final int ABSOLUTE = 0;

    /**
     * The specified dimension holds a float and should be multiplied by the
     * height or width of the object being animated.
     * 相对与自身的宽/高的百分比,1.0 == 100%
     */
    public static final int RELATIVE_TO_SELF = 1;

    /**
     * The specified dimension holds a float and should be multiplied by the
     * height or width of the parent of the object being animated.
     * 相对于父控件的百分比
     */
    public static final int RELATIVE_TO_PARENT = 2;

demo

    ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.5f, 1.0f, 1.5f);
    scaleAnimation.setDuration(2000);
    scaleAnimation.setFillAfter(true);
    alphaImageView.startAnimation(scaleAnimation);


把构造方法加上pivot,
    ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.5f, 1.0f, 1.5f, 175f, 175f);

我们把缩放起点设置为175,那么它的缩放就从这个起点向两边开始缩放

    ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.5f, 1.0f, 1.5f,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);   

我们把它的起点模式改为relative_to_self,pivotX 和 pivotY改为0.5,意思就是它的缩放起点变为这个view的宽高的中点,向两边放大至原来的1.5倍
* @param fromXType Specifies how fromXValue should be interpreted. One of
 * Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
 * Animation.RELATIVE_TO_PARENT.

fromXType 就是用于解释解释fromCValue,其余的也是同样意思,和上面的ScaleAnimation

TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 1.0f, 
Animation.ABSOLUTE,0, Animation.ABSOLUTE, 0);

translateAnimation.setDuration(2000);
translateAnimation.setFillAfter(true);
alphaImageView.startAnimation(translateAnimation);

不放图了.....

RotateAnimation

RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(2000);
rotateAnimation.setFillAfter(true);
alphaImageView.startAnimation(rotateAnimation);  

围绕图片中心转一圈,

AnimationSet

<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fillAfter="true">

    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0"/>
    
    <scale
        android:fromXScale="0.1"
        android:fromYScale="0.1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0"/>

    <translate
        android:fromXDelta="-50%p"
        android:toXDelta="0"/>
</set>

这里说一下50% 和 -50%p ,单纯只是%就是基于view本身,也就Animation.RELATIVE_TO_SELF,而%p就是基于view的parent,也就是Animation.RELATIVE_TO_PARENT.


图中的view宽度为60px,父view为100px,左右两边平分,各为20px,针对view的动画

<translate
        android:fromXDelta="-50%p"
        android:toXDelta="0"/>

这个的意思就是:

view动画的开始位置是:view在图中的位置向左移动距离(0.5 * 100 = 50 ,为什么是左,-50%p)px,就是view在图片当前的位置向左移动50px就开始动画,这个移动的过程当然是看不到的,并且这不是view真正的移动,这里只是文字表述,view其实一直不改变它所在的位置。

结束位置就是view当前所在的位置,也就是view的左边距离父的左边20px

Interpolator

通过定义Interpolator可以改变动画的速率,比如加速,减速,匀速等,Android定义了一系列的interpolator


accelerate decelerate interpolator

动画开始和动画结束的时候速度较慢,中间的速度较快。默认的插值器就是这个,在xml中的引用

android:interpolator="@android:anim/accelerate_decelerate_interpolator"

accelerate interpolator

动画从开始到结束的过程中一直加速,有个参数factor,就是设置速率的变化的,factor默认是1.0,factor的值越大 ,开始的速度就会变得更加慢,结束的速度更加快。

  • TimeInterpolator 时间插值器
  • fraction 一个0-1的分数,由Animator 根据 当前动画播放时间/duration ,再经过xxxInterpolator计算,不同的interpolator结果不一样
  • TypeEvaluator 根据fraction的值计算出动画改变属性的属性值
  • ValueAnimator

    ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setDuration(2000);//设置动画时间,默认是300
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());//设置插值器,默认也是这个
        valueAnimator.setFloatValues(0, 200);//设置开始值和结束值
    
    
        //监听属性值的改变 
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float tem = (float) animation.getAnimatedValue();
                Log.d(TAG, "onAnimationUpdate: " + tem);
                view.setTranslationY(tem);
    
            }
        });
        //开始动画
        valueAnimator.start();
    

    第一个参数就是动画应用在哪个对象,第二个参数就是设置这个动画改变的属性,第三个可变参数,写一个就是属性的开始值,两个就是一个开始值一个结束值。这里改变的属性值必须有setXxx方法,因为是通过反射调用设置这个属性的,还有就是这这个方法中必须包含对这个view 的重绘的方法,view.postInvalidate(); / view.invalidate();否则你设置了这个属性也不能在界面上马上看到效果,也就没有动画可言。
  • addUpdateListener 每次对应的TypeEvaluate计算完属性值都会回调这个方法
  • addListener 动画的开始结束取消重复监听,可以使用AnimatorListenerAdapter代替,自己选择监听哪个
  • TypeEvaluate

    自定义TypeEvaluate

    实现抛物线,x方向是100px/s,y方向的加速度是200px/s*s

     ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator<PointF>() {
            @Override
            public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
    
                PointF pointF = new PointF();
                //fuction = t /duration
                pointF.x = 100 * 2 * fraction;
                pointF.y = 0.5f * 200 * 2 * fraction * 2 * fraction;
    
                return pointF;
            }
        }, new PointF(0, 0));
    
        animator.setDuration(2000);
    
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointF p = (PointF) animation.getAnimatedValue();
    
                view.setTranslationX(p.x);
                view.setTranslationY(p.y);
            }
        });
        animator.start();
    

    xml实现

    objectAnimator

    <?xml version="1.0" encoding="utf-8"?>
    <objectAnimator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2000"
        android:interpolator="@android:anim/linear_interpolator"
        android:propertyName="y"
        android:valueFrom="0.0"
        android:valueTo="300.0"
        android:valueType="floatType">
    
    </objectAnimator>
    

        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.value_animator);
        animator.setTarget(view);
        animator.start();
    

    animatorSet

    <?xml version="1.0" encoding="utf-8"?>
    <set
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:ordering="together">
        <objectAnimator
            android:duration="3000"
            android:interpolator="@android:anim/linear_interpolator"
            android:propertyName="scaleX"
            android:valueFrom="1.0"
            android:valueTo="0.2"
            android:valueType="floatType"
            />
    
        <objectAnimator
            android:duration="3000"
            android:interpolator="@android:anim/linear_interpolator"
            android:propertyName="scaleY"
            android:valueFrom="1.0"
            android:valueTo="0.2"
            android:valueType="floatType"
            />
        <objectAnimator
            android:duration="3000"
            android:interpolator="@android:anim/linear_interpolator"
            android:propertyName="rotationX"
            android:valueFrom="0"
            android:valueTo="360"
            android:valueType="floatType"
            />
        
    </set>
    

    java

    AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.value_animator_set);
    set.setTarget(view);
    
    set.start();
    

    set中的一个参数就是ordering,顺序可以选择together(同一时间所有动画一起开始),也可以选择sequentially(按set中的顺序顺序一个个开始)。
    纯java animatorSet

    AnimatorSet set= new AnimatorSet();
    
        set.play(AnimatorInflater.loadAnimator(this, R.animator.value_animator)).
                with(new ObjectAnimator().setDuration(2000).ofFloat(view, "x", 0, 200));
    
    
        set.setTarget(view);
        set.setDuration(2000);
    
        set.start();
    

    https://github.com/lijinxiong/note/blob/master/Android/%E5%8A%A8%E7%94%BB.md

    相关文章

    网友评论

      本文标题:Android动画

      本文链接:https://www.haomeiwen.com/subject/pchotxtx.html