关于动画的使用

1、概述

Android提供了几种动画类型:

  • View Animation(Tween Animation)
  • Drawable Animation(Frame Animation)
  • Property Animation

    View Animation相当简单,不过只能支持简单的缩放、平移、旋转、透明度基本的动画,且有一定的局限性。比如:你希望View有一个颜色的切换动画;你 希望可以使用3D旋转动画;你希望当动画停止时,View的位置就是当前的位置;这些View Animation都无法做到。这就是Property Animation产生的原因。View Animation 移动控件之后,控件的点击事件还在原地,而Property Animation的控件点击事件会移动到动画结束的地方。

2、相关API

Property Animation就是通过动画的方式改变对象的属性,属性:
Duration动画的持续时间,默认300ms。
Time interpolation:时间差值,类似于LinearInterpolator、AccelerateDecelerateInterpolator,定义动画的变化率。
TypeEvaluator:根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值
Repeat count and behavior:重复次数、以及重复模式;可以定义重复多少次;重复时从头开始,还是反向。
Animator sets: 动画集合,你可以定义一组动画,一起执行或者顺序执行。
Frame refresh delay:帧刷新延迟,对于你的动画,多久刷新一次帧;默认为10ms,但最终依赖系统的当前状态;基本不用管。
ViewPropertyAnimator:

相关的类
ObjectAnimator 动画的执行类,
ValueAnimator 动画的执行类,
AnimatorSet 用于控制一组动画的执行:线性,一起,每个动画的先后执行等。
AnimatorInflater 用户加载属性动画的xml文件
TypeEvaluator 类型估值,主要用于设置动画操作属性的值。
TimeInterpolator 时间插值
总的来说,属性动画就是,动画的执行类来设置动画操作的对象的属性、持续时间,开始和结束的属性值,时间差值等,然后系统会根据设置的参数动态的变化对象的属性。
TypeEvalutors
根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值,android提供了以下几个evalutor:
● IntEvaluator:属性的值类型为int;
● FloatEvaluator:属性的值类型为float;
● ArgbEvaluator:属性的值类型为十六进制颜色值;
● TypeEvaluator:一个接口,可以通过实现该接口自定义Evaluator。
自定义TypeEvalutor很简单,只需要实现一个方法,如FloatEvalutor的定义:

public class FloatEvaluator implements TypeEvaluator {
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}

自定义TypeEvalutor会取代默认的值返回

PropertyValuesHolder
PropertyValuesHolder的效果和AnimatorSet,ViewPropertyAnimator一样:

    PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
    PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
    ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
    ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
    ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
    AnimatorSet animSetXY = new AnimatorSet();
    animSetXY.playTogether(animX, animY);
    animSetXY.start();
    myView.animate().x(50f).y(100f);

TimeInterplator
Time interplator定义了属性值变化的方式,如线性均匀改变,开始慢然后逐渐快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,这两个是一样的,在3.0之前只有Interplator,3.0之后实现代码转移至了 TimeInterplator。Interplator继承自TimeInterplator,内部没有任何其他代码。
● AccelerateInterpolator      加速,开始时慢中间加速
● DecelerateInterpolator       减速,开始时快然后减速
● AccelerateDecelerateInterolator  先加速后减速,开始结束时慢,中间加速
● AnticipateInterpolator       反向 ,先向相反方向改变一段再加速播放
● AnticipateOvershootInterpolator  反向加回弹,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
● BounceInterpolator        跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
● CycleIinterpolator         循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
● LinearInterpolator         线性,线性均匀改变
● OvershottInterpolator       回弹,最后超出目的值然后缓慢改变到目的值
● TimeInterpolator         一个接口,允许你自定义interpolator,以上几个都是实现了这个接口

当Layout改变时应用动画
ViewGroup中的子元素可以通过setVisibility使其Visible、Invisible或Gone,当有子元素可见性改变时(VISIBLE、GONE),可以向其应用动画,通过LayoutTransition类应用此类动画:
ViewGroup.setLayoutTransition(LayoutTransition transition)
transition.setAnimator(LayoutTransition.DISAPPEARING, customDisappearingAnim);
通过setAnimator应用动画,第一个参数表示应用的情境,可以以下4种类型:
● APPEARING        当一个元素在其父元素中变为Visible时对这个元素应用动画
● CHANGE_APPEARING    当一个元素在其父元素中变为Visible时,因系统要重新布局有一些元素需要移动,对这些要移动的元素应用动画
● DISAPPEARING       当一个元素在其父元素中变为GONE时对其应用动画
● CHANGE_DISAPPEARING  当一个元素在其父元素中变为GONE时,因系统要重新布局有一些元素需要移动,这些要移动的元素应用动画.
第二个参数为一Animator。
mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
此函数设置动画延迟时间,参数分别为类型与时间。

3、实际使用

1)ObjectAnimator

①简单使用

   ObjectAnimator//
   .ofFloat(view, "rotationX", 0.0F, 360.0F)//
   .setDuration(500)//
   .start();
ObjectAnimator.ofFloat(expandedImageView, View.X,
                            startBounds.left).start();

②设置背景颜色(View中有setBackgroundColor(@ColorInt int color)方法,所以可以直接使用”backgroundColor”的propertyName):

    ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", RED, BLUE);
    colorAnim.setDuration(3000);
    colorAnim.setEvaluator(new ArgbEvaluator());
    colorAnim.setRepeatCount(ValueAnimator.INFINITE);
    colorAnim.setRepeatMode(ValueAnimator.REVERSE);
    colorAnim.start();

③多个ObjectAnimator的简单写法:

    ObjectAnimator anim1 = ObjectAnimator.ofFloat(balls.get(0), "y",
                        0f, getHeight() - balls.get(0).getHeight()).setDuration(500);
    ObjectAnimator anim2 = anim1.clone();
    anim2.setTarget(balls.get(1));

④实现一个动画更改多个效果有两种方法:
使用propertyValuesHolder

    public void propertyValuesHolder(View view)
     {
      PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,
    0f, 1f);
      PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f,
        0, 1f);
      PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f,
        0, 1f);
      ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start();
     }
使用AnimatorSet 
    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 和propertyValuesHolder一起使用:

  AnimatorSet set = new AnimatorSet();
                set.play(
                        ObjectAnimator.ofFloat(expandedImageView, View.X,
                                startBounds.left))
                        .with(ObjectAnimator.ofFloat(expandedImageView, View.Y,
                                startBounds.top))
                        .with(ObjectAnimator.ofFloat(expandedImageView,
                                View.SCALE_X, startScaleFinal))
                        .with(ObjectAnimator.ofFloat(expandedImageView,
                                View.SCALE_Y, startScaleFinal));

2)自定义propertyName

源码:

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setFloatValues(values);
        return anim;
    }

target : 执行动画的目标
propertyName : 目标对象中所有的set/get方法,如果需要自定义propertyName,只需要在target的类中添加set方法即可.
propertyName 自定义:

ObjectAnimator animator = ObjectAnimator.ofFloat(CustomView.this,
                "customPhase", 1.0f, 0.0f);
        animator.setDuration(10000);
        animator.start();

//写一个public的方法,set后面的就是propertyName(propertyName第一个字母不需要大写,后面的首字母都需要大写,否则无效).

    public void setCustomPhase(float phase) {
        Log.d("pathview", "setPhase called with:" + String.valueOf(phase));
        paint.setPathEffect(createPathEffect(length, phase, 0.0f));
        invalidate();// will calll onDraw
    }

3)自定义Property

源码:

public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
            float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, property);
        anim.setFloatValues(values);
        return anim;
    }

        public CustomProperty(Class<Float> type, String name) {
            super(type, name);
        }

        @Override
        public Float get(View view) {
            return 0f;
        }

        @Override
        public void set(View view, Float value) {
            view.setTranslationX(view.getWidth() * value);
            view.setTranslationY(view.getHeight() * value);
            view.setAlpha(value);
            view.setRotation(360 * value);
        }

    }
      ObjectAnimator animator = ObjectAnimator.ofFloat(btn,
                new CustomProperty(Float.TYPE, "custom"), 0, 1);
        animator.setRepeatMode(ObjectAnimator.REVERSE);
        animator.setRepeatCount(Integer.MAX_VALUE);
        animator.start();

常用的propertyName:
● translationX and translationY
● rotation, rotationX, and rotationY
● scaleX and scaleY
● pivotX and pivotY
● x and y
● alpha

ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。
当对于属性值,只设置一个的时候,会认为对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束
动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法

4)ValueAnimator实现动画

不需要操作的对象的属性一定要有getter和setter方法,可以根据当前动画的计算值,来操作任何属性,

public void verticalRun(View view)
 {
  ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight
    - mBlueBall.getHeight());
  animator.setTarget(mBlueBall);
  animator.setDuration(1000).start();
 }

/**
  * 自由落体
  * @param view
  */
 public void verticalRun( View view)
 {
  ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight
    - mBlueBall.getHeight());
  animator.setTarget(mBlueBall);
  animator.setDuration(1000).start();
// animator.setInterpolator(value)
  animator.addUpdateListener(new AnimatorUpdateListener()
  {
   @Override
   public void onAnimationUpdate(ValueAnimator animation)
   {
    mBlueBall.setTranslationY((Float) animation.getAnimatedValue());
   }
  });
 }

/**
  * 抛物线
  * @param view
  */
 public void paowuxian(View view)
 {

  ValueAnimator valueAnimator = new ValueAnimator();
  valueAnimator.setDuration(3000);
  valueAnimator.setObjectValues(new PointF(0, 0));
  valueAnimator.setInterpolator(new LinearInterpolator());
  valueAnimator.setEvaluator(new TypeEvaluator<PointF>()
  {
   // fraction = t / duration
   @Override
   public PointF evaluate(float fraction, PointF startValue,
     PointF endValue)
   {
    Log.e(TAG, fraction * 3 + "");
    // x方向200px/s ,则y方向0.5 * 10 * t
    PointF point = new PointF();
    point.x = 200 * fraction * 3;
    point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
    return point;
   }
  });

  valueAnimator.start();
  valueAnimator.addUpdateListener(new AnimatorUpdateListener()
  {
   @Override
   public void onAnimationUpdate(ValueAnimator animation)
   {
    PointF point = (PointF) animation.getAnimatedValue();
    mBlueBall.setX(point.x);
    mBlueBall.setY(point.y);

   }
  });
 }

5)监听动画的事件

每次执行addListener(AnimatorListener listener)方法都会添加一个AnimatorListener到ObjectAnimator中(如果每次都是new AnimatorListener ,那么会添加很多个对象,如果是同一个AnimatorListener ,那么会将它重复添加到ObjectAnimator),所以addListener()方法和new AnimatorListener()不能被重复执行.

public void fadeOut(View view)
 {
  ObjectAnimator anim = ObjectAnimator.ofFloat(mBlueBall, "alpha", 0.5f);

  anim.addListener(new AnimatorListener()
  {

   @Override
   public void onAnimationStart(Animator animation)
   {
    Log.e(TAG, "onAnimationStart");
   }

   @Override
   public void onAnimationRepeat(Animator animation)
   {
    // TODO Auto-generated method stub
    Log.e(TAG, "onAnimationRepeat");
   }

   @Override
   public void onAnimationEnd(Animator animation)
   {
    Log.e(TAG, "onAnimationEnd");
    ViewGroup parent = (ViewGroup) mBlueBall.getParent();
    if (parent != null)
     parent.removeView(mBlueBall);
   }

   @Override
   public void onAnimationCancel(Animator animation)
   {
    // TODO Auto-generated method stub
    Log.e(TAG, "onAnimationCancel");
   }
  });
  anim.start();
 }
AnimatorListenerAdapter继承了AnimatorListener接口
  anim.addListener(new AnimatorListenerAdapter()
  {
   @Override
   public void onAnimationEnd(Animator animation)
   {
    Log.e(TAG, "onAnimationEnd");
    ViewGroup parent = (ViewGroup) mBlueBall.getParent();
    if (parent != null)
     parent.removeView(mBlueBall);
   }
  });
  ```
###6)AnimatorSet的使用

//第一:使用playTogether两个动画同时执行,当然还有playSequentially依次执行

public void togetherRun(View view)
{
ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, “scaleX”,
1.0f, 2f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, “scaleY”,
1.0f, 2f);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(2000);
animSet.setInterpolator(new LinearInterpolator());
//两个动画同时执行
animSet.playTogether(anim1, anim2);
animSet.start();
}
“`
//第二:如果我们有一堆动画,如何使用代码控制顺序,比如1,2同时;3在2后面;4在1之前等~就是效果2了

public void playWithAfter(View view)
 {
  float cx = mBlueBall.getX();

  ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX",
    1.0f, 2f);
  ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY",
    1.0f, 2f);
  ObjectAnimator anim3 = ObjectAnimator.ofFloat(mBlueBall,
    "x",  cx ,  0f);
  ObjectAnimator anim4 = ObjectAnimator.ofFloat(mBlueBall,
    "x", cx);

  /**
   * anim1,anim2,anim3同时执行
   * anim4接着执行
   */
  AnimatorSet animSet = new AnimatorSet();
  animSet.play(anim1).with(anim2);
  animSet.play(anim2).with(anim3);
  animSet.play(anim4).after(anim3);
  animSet.setDuration(1000);
  animSet.start();
 }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值