您的位置:首页 > 移动开发 > Android开发

Android 属性动画

2015-11-20 15:57 465 查看
一:属性动画简介

Android 属性动画是API 11引入的,更在的版本可以使用Nineoldandroids来实现,Nineoldandroids官方网站http://nineoldandroids.com。
Nineoldandroids对属性动画做了兼容,在API 11之前的版本通过代理View动画来实现,因此在API 11之前的版本,本质还是View动画。Nineoldandroids的功能和系统原生的android,animation.*中类的功能用法完全一致。比较常用的几个动画类是:ValueAnimator,ObjectAnimator和AnimatorSet,其中ObjectAnimator继承自ValueAnimator,AnimatorSet是动画集合。
先看几个小列子:


1.

ObjectAnimator.ofInt(myObjec,"width",500).setDuration(5000).start();


上面这句代码的作用就是使用ObjectAnimator属性动画来让myObjec这个对象的width属性在5s变为500px。


2.

ObjectAnimator.ofFloat(myObjec,"translationY", -myObjec.getHeight()).start();


上面这段代码的作用就是改变对象myObjec的translationY属性,让其沿着Y轴向上平移一段距离(myObjec的高度)。


3.

AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(myObjec, "alpha", 1,0.5f,1),
ObjectAnimator.ofFloat(myObjec, "rotationX", 0,180),
ObjectAnimator.ofFloat(myObjec, "rotationY", 0,270),
ObjectAnimator.ofFloat(myObjec, "translationY", 0,100),
ObjectAnimator.ofFloat(myObjec, "translationX", 0,100),
ObjectAnimator.ofFloat(myObjec, "rotation", 0,-270),
ObjectAnimator.ofFloat(myObjec, "scaleX", 1,1.2f),
ObjectAnimator.ofFloat(myObjec, "scaleY", 1,0.5f)
);
set.setDuration(5000).start();


上面代码的作用在5s内对View做了透明度,旋转,平移,缩放动画。

从上面3个小例子不难看出,对一个view使用属性动画的代码还是比较容易理解的,当然,属性动画也可以通过XML来定义。
需要定义在res/animator目录下面。其大概样式如下:


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together" >

<objectAnimator
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="0.5" >
</objectAnimator>
<animator
android:duration="1000"
android:valueFrom="1"
android:valueTo="0.5" >
</animator>

</set>


下面对标签说明下:

objectAnimator标签属性:

android:propertyName——表示属性动画的作用对象的属性名称;

android:duration——动画的时长;

android:valueFrom——表示属性的起始值;

android:valueTo——表示属性的结束值;

android:startOffset——动画的延迟时间;

android:repeatCount——动画的重复次数(默认值0,-1表示无限循环);

android:repeatMode——动画的重复模式(“repeat”表示连续重复,“reverse”表示逆向重复。);

android:valueType——表示android:propertyName所指属性的类型,有“intType”和“floatType”两个可选,分别表示属性的类型为整形和浮点型。(如果android:propertyName所指的属性为颜色,那么不需要指定android:valueType,系统会自动做处理)。

使用XML定义的属性动画非常简单,代码大概如下:

Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scale);
anim.setTarget(mMv);
anim.start();


二:属性动画的监听器

属性动画提供了监听器用于监听动画的播放过程,主要有AnimatorUpdateListener和AnimatorListener。
AnimatorListener的定义如下:


public static Interface AnimatorListener{
void onAnimationStart(Animator arg0);
void onAnimationRepeat(Animator arg0);
void onAnimationEnd(Animator arg0);
void onAnimationCancel(Animator arg0);
}


从定义中可以看出它可以监听动画的开始、结束、取消以及重复播放。使用起来也很简单因为系统提供了AnimatorListener的适配器。使用代码如下:

ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addListener(new AnimatorListener() {

@Override
public void onAnimationStart(Animator arg0) {
// TODO Auto-generated method stub
}

@Override
public void onAnimationRepeat(Animator arg0) {
// TODO Auto-generated method stub
}

@Override
public void onAnimationEnd(Animator arg0) {
// TODO Auto-generated method stub
}

@Override
public void onAnimationCancel(Animator arg0) {
// TODO Auto-generated method stub
}
});


三:高级使用

首先先分析下属性动画的原理:

属性动画要求动画作用的对象提供该属性的set和get方法,属性动画根据外界传递的初始值和最终值,以动画的效果多次去调用set方法,没次传递给set方法的值都不一样,确切说是随着时间的推移,所传递的值越来越接近最终的值。那么想要给object的属性A做动画,那么必须要满足以下两个条件:

(1)object必须提供setA方法,如果动画开始的时候没有传递初始值,那么还要提供getA方法,因为系统要调用getA方法去获取初始值。

(2)object的setA对属性A所做的改变必须能够通过某种方式反映出来,比如会带来UI的变换之类的否则动画无效果。

例如,想给一个Button增加一个动画,使他的宽在5s内增加到500px。从Button的源码可以知道Button继承自TextView其getWidth获取的是其宽度,但是其setWidth是TextView和其子类的专属方法,它的作用不是设置View的宽度,而是设置TextView的最大宽度和最小宽度。其实就是,TextView的宽度对应XML中的android:layout_width属性,而TextView还有一个属性android:width,这个属性就对应了setWidth方法。所以通过setWidth无法改变控件的宽度。官方文档对于这种情况给出了3中解决方法:

1.给你的对象加上get和set方法,如有你有权限的话;

2.用一个类来包装原始对象,间接的为其提供get和set方法;

3.采用ValueAnimator监听动画过程,自己实现属性变化。

这里发现第一种方案可行性极低,因为我们通常是没有修改这些组件的权限的。下面用代码来实现以下第二中方案,先看代码:

private void performAnimate(){
ViewWrapper wrapper = new ViewWrapper(button,button.getWidth());
ObjectAnimator.ofInt(wrapper,"width",500).setDuration(5000).start();
}

private static class ViewWrapper{
private View mTarget;
private int mWidth;

public ViewWrapper(View target,int width){
mTarget = target;
mWidth = width;
}

public int getWidth(){
//return mTarget.getLayoutParams().width;
return mWidth;
}

public void setWidth(int width){
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}

}


从上面代码中不难看出我们首先是定义了一个类(ViewWrapper)来包装原始对象(Button),然后通过ViewWrapper的get和set方法来改变原对象的宽度。

对于第三种解决方案,同样先看代码:

private void performAnimate(final View target, final int start, final int end) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {

// 持有一个IntEvaluator对象,方便下面估值的时候使用
private IntEvaluator mEvaluator = new IntEvaluator();

@Override
public void onAnimationUpdate(ValueAnimator animator) {
// 获得当前动画的进度值,整型,1-100之间
int currentValue = (Integer) animator.getAnimatedValue();
Log.d(TAG, "current value: " + currentValue);

// 获得当前进度占整个动画过程的比例,浮点型,0-1之间
float fraction = animator.getAnimatedFraction();
// 直接调用整型估值器通过比例计算出宽度,然后再设给Button
target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
target.requestLayout();
}
});

valueAnimator.setDuration(5000).start();
}


上面的代码,会在5s内将一个数从1变到100,然后动画的每一帧都会调用onAnimationUpdate方法,在这个方法内可以获取当前的值和当前值所占的比例,就可以计算出此刻的宽度是多少,例如时间过了一半,那么当前值应该是50,比例是0.5,假设Button的初始宽度是100px,最终宽度是500px,那么此时的Button应该增加了(500-100)*0.5=200,那么当前的宽度应该是100+200=300。

到此属性动画大概讲述了一遍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: