关于动画的使用

来源:互联网 发布:淘宝自检工具 编辑:程序博客网 时间:2024/05/13 04:39

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(); }
原创粉丝点击