您的位置:首页 > 移动开发 > Objective-C

Android属性动画之ObjectAnimator和AnimatorSet

2017-07-29 16:58 621 查看

一 前言

ValueAnimator是监听动画的过程,自己实现属性的改变,详见《 Android属性动画之ValueAnimator》,但是ObjectAnimator就有所不同,它继承了ValueAnimator,它真正可以作用在一个对象上,并且明确的指定了要更改的属性,属性的变化过程是它帮我们完成的,不需要我们自己来实现它的改变。转载请注明出处:小石头的博客
http://blog.csdn.net/lu1024188315/article/details/74518599

ObjectAnimator

1 获取实例的方法

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)

public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
float... values)

public static ObjectAnimator ofInt(Object target, String propertyName, int... values)

public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values)

public static ObjectAnimator ofObject(Object target, String propertyName,
TypeEvaluator evaluator, Object... values)

public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
TypeEvaluator<V> evaluator, V... values)

public static ObjectAnimator ofPropertyValuesHolder(Object target,
PropertyValuesHolder... values)


参数分析:
(1)target:ObjectAnimator作用的对象,即要被设置动画的对象
(2)propertyName:对象target的属性,这个属性值将在values范围内就行逐渐变化,以现实动画效果
(3)values:属性propertyName值变化范围

(4)TypeEvaluator:类型估值器,在《 Android属性动画之ValueAnimator》文章中有。
(5)PropertyValuesHolder:用来保存属性信息和这个属性的值,在《 Android属性动画之ValueAnimator》文章中有。

(6)Property:要使用一个类继承Property,进一步实现获取与设置propertyName的get、set方法,详见下文

2 常有方法

public void setTarget(Object target)
设置目标对象

public ObjectAnimator setDuration(long duration)
设置持续时间

public void setProperty(Property property)
设置属性

public void setPropertyName(String propertyName)
设置属性名称

public void setIntValues(int... values)
设置Int值,对应ObjectAnimator.ofInt

public void setFloatValues(float... values)
设置Float,对应ObjectAnimator.ofFloat

public void setObjectValues(Object... values)
设置Object值,对应ObjectAnimator.ofObject


3 使用实例

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img, "translationX", 0.0f, 350.0f, 0f);
objectAnimator.setDuration(2000);//动画时间
objectAnimator.setInterpolator(new BounceInterpolator());//动画插值
objectAnimator.setRepeatCount(-1);//设置动画重复次数
objectAnimator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式
objectAnimator.setStartDelay(1000);//动画延时执行
objectAnimator.start();//启动动画
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator animation){
//根据变化值来设置imageView对象的Y轴坐标,这样就实现了imageView的垂直移动
//                img.setTranslationY((Float) animation.getAnimatedValue());
}
});

objectAnimator.addListener(new Animator.AnimatorListener() {
//动画开始
@Override
public void onAnimationStart(Animator animation) {
}
//动画结束
@Override
public void onAnimationEnd(Animator animation) {

}
//动画取消
@Override
public void onAnimationCancel(Animator animation) {

}
//动画重复
@Override
public void onAnimationRepeat(Animator animation) {

}
});
objectAnimator.addPauseListener(new Animator.AnimatorPauseListener() {
//动画暂停
@Override
public void onAnimationPause(Animator animation) {

}
//动画重启
@Override
public void onAnimationResume(Animator animation) {

}
});


说明,可以看到在上面已经明确指定了属性名称translationX,这样整个改变过程内部已经帮我们完成,也就是说在ValueAnimator中我们只能获取到变化的值,属性值的更改过程由我们自己来完成,而在ObjectAnimator中,它帮我们做了两件事,首先获取到变化值,然后通过上面指定的属性名称来进行属性值的修改。
效果图:



三 属性动画原理分析

从上面的例子我们看到ObjectAnimator需要指定变化的属性名,当它获取到变化值后,就会通过这个属性名的set方法来设置这个属性值。属性动画根据你传递的该属性的初始值和最终值,动态的去调用set方法,每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。所以,所以必须为对象对应的属性提供get、set方法。

下面总结一下:

(1). objectObjectAnimator必须要提供setXxx方法,如果动画的时候没有传递初始值,那么还要提供getXxx方法,因为系统要去拿xxx属性的初始值。

(2). 另外设置属性值之后,应该使用requestLayout()或者invalidate()去进行刷新操作,这样才能看到动画效果。

当我们需要对某个对象的属性进行动画,但是这个属性没有提供对应的getXxx()、setXxx()方法该怎么办,我们有三种方法可以做:

a:给你的对象加上get和set方法,如果你有权限的话

b:用一个类来包装原始对象,间接为其提供get和set方法

c:采用ValueAnimator,监听动画过程,自己实现属性的改变

另外,我们我们看到每一种动画属性都有两种方式一种是指定属性名,一种是指定一个Property对象,它对应的就是我们的自定义属性。假如我们希望更改我们自定义的某个属性,我们就可以使用这个,原理是相同的,就是不断的修改对应的属性值,下面来举个例子,假如我们自定义了一个圆,我们希望这个圆可以做一个动画就是半径可以指定的范围内进行变化。

1 自定义圆CircleAnim,它有三个属性:中心点坐标和半径:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleAnim">
<attr name="pivotX" format="dimension"/>
<attr name="pivotY" format="dimension"/>
<attr name="radius" format="dimension"/>
</declare-styleable>

</resources>


public class CircleAnim  extends View {
private float mPivotX;
private float mPivotY;
private float mRadius;
private Paint mPaint;

public CircleAnim(Context context) {
this(context, null);
}

public CircleAnim(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public CircleAnim(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleAnim);
mPivotX = ta.getDimension(R.styleable.CircleAnim_pivotX, 0);
mPivotY = ta.getDimension(R.styleable.CircleAnim_pivotY, 0);
mRadius = ta.getDimension(R.styleable.CircleAnim_radius, 0);
ta.recycle();

init();
}

private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.parseColor("#0F000F"));
}

public void setRadius(float radius) {
mRadius = radius;
invalidate();
}

public float getRadius() {
return mRadius;
}

@Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(mPivotX, mPivotY, mRadius, mPaint);
super.onDraw(canvas);
}
}


假如我们希望这个圆实现一个动画,就是变径在指定的范围内改变。
xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.eric.windows.anima.CircleAnim
android:id="@+id/circle"
app:pivotX="150dp"
app:pivotY="100dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>


Activity使用:

public class MainActivity extends AppCompatActivity {
private CircleAnim mCircleAnim;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCircleAnim = (CircleAnim) findViewById(R.id.circle);
final ObjectAnimator animator = ObjectAnimator.ofFloat(mCircleAnim, new RadiusProperty(CircleAnim.class, "CircleAnim"), 0, dp2px(40));
animator.setDuration(5000);

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator.start();
}
});
}

private float dp2px(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
}


可以看到我们指定变化属性为RadiusProperty,这个是我们自定义的属性,实现如下:

class RadiusProperty extends Property<CircleAnim, Float> {
public RadiusProperty(Class type, String name) {
super(type, name);
}

@Override
public Float get(CircleAnim object) {
return object.getRadius();
}

@Override
public void set(CircleAnim object, Float value) {
object.setRadius(value);
}
}


在动画的执行过程中会不断的去通过调用set函数去设置变化的变径,在这个里面我们调用的就是CircleAnim的setRadius函数来设置我们圆的变径,在setRadius里面得到这个变径之后,调用invalidate函数,这样进行重绘就会画出指定变径的圆,由于整个过程是连续的,所以就实现了一个半径不断变化的动画效果。
效果图:



2 set、get函数分析

回到到上面的示例:

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img, "translationX", 0.0f, 350.0f, 0f);
objectAnimator.setDuration(2000);//动画时间
objectAnimator.setInterpolator(new BounceInterpolator());//动画插值
objectAnimator.setRepeatCount(-1);//设置动画重复次数
objectAnimator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式
objectAnimator.setStartDelay(1000);//动画延时执行
objectAnimator.start();//启动动画


在这里的示例中,貌似没有设置Property对象,那么系统是如何获取set、get函数,只有到源码中找了
ObjectAnimator#ofFloat,如下:

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


继续看setFloatValues函数,ObjectAnimator#setFloatValues,如下:

private Property mProperty;
public void setFloatValues(float... values) {
if (mValues == null || mValues.length == 0) {
// No values yet - this animator is being constructed piecemeal. Init the values with
// whatever the current propertyName is
if (mProperty != null) {//mProperty 不为null,直接使用mProperty
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
} else {//否则的话,必须指定属性名
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
}
} else {
super.setFloatValues(values);
}
}


说明,mProperty 不为null,直接使用mProperty,否则的话,必须指定属性名,当然在这里mProperty为null,如何调用下面这个函数获取ObjectAnimator实例时,mProperty不为null,如下:

public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
float... values)


继续下去,很难找到和get、set相关的内容,索性就放弃了,不过呐,在PropertyValuesHolder中有这两个成员变量

Method mSetter = null;
private Method mGetter = null;


说明,嘿嘿,很怀疑它们就是我们要找的set,get方法,那么就看看它们是如何赋值的:

void setupSetter(Class targetClass) {
Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
}

private void setupGetter(Class targetClass) {
mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
}


说明,这两个函数都在PropertyValuesHolder中,接着看setupSetterOrGetter函数:

 private Method setupSetterOrGetter(Class targetClass,
HashMap<Class, HashMap<String, Method>> propertyMapMap,
String prefix, Class valueType) {
Method setterOrGetter = null;
synchronized(propertyMapMap) {
//如果propertyMap中已经存在这个方法那么直接拿来使用吧
HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
boolean wasInMap = false;
if (propertyMap != null) {
wasInMap = propertyMap.containsKey(mPropertyName);
if (wasInMap) {
setterOrGetter = propertyMap.get(mPropertyName);
}
}
if (!wasInMap) {
//在这里调用getPropertyFunction通过反射机制取得我们需要函数,具体怎么得到的咱就不淘汰
setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
if (propertyMap == null) {
propertyMap = new HashMap<String, Method>();
propertyMapMap.put(targetClass, propertyMap);
}//把获取的get/set保存到propertyMap集合中 其实是保存到了成员变量sSetterPropertyMap中
propertyMap.put(mPropertyName, setterOrGetter);
}
}
return setterOrGetter;
}
说明,好,到这里知道了set、get的方法是怎么来的,那么它们又是怎么被调用的呐?只能继续找mSetter、mGetter相关内容了,找来找去发现


mSetter、mGetter只调用下面这个函数:

public native Object invoke(Object receiver, Object... args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;


说明,这个函数在Method类中,很明显他是个native函数,那么它的作用是什么鬼?好,接下来来个小插曲来说明它的作用:
先自定义一个类,如下:

public class A {
  public void foo(String name) {
    System.out.println("Hello, " + name);
  }
}


使用反射机制获取foo方法,然后调用invoke函数看看得出什么结论:

import java.lang.reflect.Method;

public class TestClassLoad {
  public static void main(String[] args) throws Exception {
    Class<?> clz = Class.forName("A");
    Object o = clz.newInstance();
    Method m = clz.getMethod("foo", String.class);
    for (int i = 0; i < 5; i++) {
      m.invoke(o, Integer.toString(i));
    }
}


看,结果如下:

Hello, 0
Hello, 1
Hello, 2
Hello, 3
Hello, 4


说明,呀,这不就是调用的foo函数,没错,这么说来上面mSetter、mGetter调用invoke函数不就是间接地调用propertyName的getXXX、setXXX的函数嘛,没错就是这样的,最难的部分搞明白了,剩下的就简单了,如何使用

public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
float... values)


这个函数获取ObjectAnimator实例,它的get、set方法是如何的呐?先看个示例:

CircleAnim  mCircleAnim = (CircleAnim) findViewById(R.id.circle);
final ObjectAnimator animator2 = ObjectAnimator.ofFloat(mCircleAnim, new FloatProperty<CircleAnim>("pivotX") {
@Override
public void setValue(CircleAnim object, float value) {
object.setRadius(value);
}

@Override
public Float get(CircleAnim object) {
return object.getRadius();
}
}, 0, 100);
animator.setDuration(5000);

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator2.start();
}
});


说明,上面的Property使用是其子类FloatProperty,而且必须要实现setValue、get抽象方法,FloatProperty源码如下:

public abstract class FloatProperty<T> extends Property<T, Float> {
public FloatProperty(String name) {
super(Float.class, name);
}
public abstract void setValue(T object, float value)
@Override
final public void set(T object, Float value) {
setValue(object, value);
}

}


说明,FloatProperty它是一个抽象类,继承了Property,其实现了Property的set方法,保留了Property的get方法,在set函数中调用抽象方法setValue,而FloatProperty的setValue方法和Property的get方法则需要我们自己去实习,嗯,FloatProperty很简单没有做太多的内容,就是对Property进一步细化,把属性values值规范为Float类型。下面看ObjectAnimator.ofFloat:,源码如下:

public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
float... values) {
//调用ObjectAnimator的构造函数创建一个ObjectAnimator实例,在这个构造函数中又调用了setProperty函数来保存property
ObjectAnimator anim = new ObjectAnimator(target, property);
//设置属性值
anim.setFloatValues(values);
return anim;
}


说明,在这里调用了ObjectAnimator构造函数,创建一个ObjectAnimator实例,其内容不看了,主要的功能就是保存了property值,记住此时的property不为null,还是来分析anim.setFloatValues,源码如下:

public void setFloatValues(float... values) {
if (mValues == null || mValues.length == 0) {
if (mProperty != null) {//此时mProperty 不为null,走这里
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
} else {
.....
}
} else {
.....
}
}


继续看PropertyValuesHolder.ofFloat:

protected Property mProperty;
public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) {
//创建一个FloatPropertyValuesHolder实例,其为PropertyValuesHolder子类,它们的关系如Property、FloatProperty的关系
return new FloatPropertyValuesHolder(property, values);
}

public FloatPropertyValuesHolder(Property property, float... values) {
super(property);//调用父类的构造方法
......
}

private PropertyValuesHolder(Property property) {
mProperty = property;//把property保存到PropertyValuesHolder的成员变量mProperty上
......
}


说明,经过一系列查找property最终被保存到了保存到PropertyValuesHolder的成员变量mProperty上,那么在PropertyValuesHolder中应该可以找到property的get、set方法的调用了,en,没错,结果发现在setupValue、setupSetterAndGetter函数中调用了get方法,在setAnimatedValue函数中set方法,如下
PropertyValuesHolder#setupValue:

private void setupValue(Object target, Keyframe kf) {
if (mProperty != null) {
////mProperty不为null 调用mProperty 的get方法
Object value = convertBack(mProperty.get(target));
kf.setValue(value);
} else {
try {
if (mGetter == null) {
Class targetClass = target.getClass();
setupGetter(targetClass);//mSetter为null则调用setupGetter函数查找get函数,上文已经说过
if (mGetter == null) {
//找不到get函数,证明ObjectAnimator作用对象的属性没有get方法,那么将会造成动画无效,
// 这也是为什么要强调:ObjectAnimator作用对象的属性必须有get、set方法的原因。
return;
}
}
//找到get函数 通过mGetter调用invoke函数,间接调用mProperty的get方法,上文已经分析过
Object value = convertBack(mGetter.invoke(target));
......
} catch (InvocationTargetException e) {
......
} catch (IllegalAccessException e) {
......
}
}
}


PropertyValuesHolder#setupSetterAndGetter:

void setupSetterAndGetter(Object target) {
......
if (mProperty != null) {
try {
......
for (int i = 0; i < keyframeCount; i++) {
Keyframe kf = keyframes.get(i);
if (!kf.hasValue() || kf.valueWasSetOnStart()) {
if (testValue == null) {
//mProperty不为null 调用mProperty 的get方法
testValue = convertBack(mProperty.get(target));
}
......
}
}
return;
} catch (ClassCastException e) {
......
}
}
if (mProperty == null) {//mProperty为null 则要使用mSetter了
Class targetClass = target.getClass();
if (mSetter == null) {//mSetter为null则调用setupSetter函数查找set函数,上文已经说过
setupSetter(targetClass);
}
......
for (int i = 0; i < keyframeCount; i++) {
Keyframe kf = keyframes.get(i);
if (!kf.hasValue() || kf.valueWasSetOnStart()) {
if (mGetter == null) {//mSetter为null则调用setupGetter函数查找get函数,上文已经说过
setupGetter(targetClass);
if (mGetter == null) {
//找不到get函数,证明ObjectAnimator作用对象的属性没有get方法,那么将会造成动画无效,
// 这也是为什么要强调:ObjectAnimator作用对象的属性必须有get、set方法的原因。
return;
}
}
try {//找到get函数 通过mGetter调用invoke函数,间接调用mProperty的get方法,上文已经分析过
Object value = convertBack(mGetter.invoke(target));
......
} catch (InvocationTargetException e) {
......
} catch (IllegalAccessException e) {
......
}
}
}
}
}


PropertyValuesHolder#setAnimatedValue:

void setAnimatedValue(Object target) {
if (mProperty != null) {
//调用set方法
mProperty.set(target, getAnimatedValue());
}
if (mSetter != null) {
try {
// 如果mProperty 为null,通过mSetter调用invoke函数,间接调用mProperty的set方法,上文已经分析过
mSetter.invoke(target, mTmpValueArray);
} catch (InvocationTargetException e) {
......
} catch (IllegalAccessException e) {
......
}
}
}


好,set、get函数学习到此,有兴趣的可以继续探讨。

四 组合动画

学习了Animator实现动画的原理,明白了get、set函数是怎么的一回事,那么接下来再来学习组合动画,实际使用中组合动画是非常重要的,组合动画有以下几种方式:

a:使用AnimatorSet
b:使用PropertyValuesHolder
c:使用ViewPropertyAnimator

接下来就是一个一个的分析了。

1 AnimatorSet

使用AnimatorSet来进行组合动画也有两种处理方式。
(1)使用AnimatorSet的play()方法

这个类有一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:

public Builder with(Animator anim)
将现有动画和传入的动画同时执行

public Builder before(Animator anim)
将现有动画插入到传入的动画之前执行

public Builder after(Animator anim)
将现有动画插入到传入的动画之后执行

public Builder after(long delay)
将现有动画延迟指定毫秒后执行


示例:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animator_set);

container = (LinearLayout) findViewById(R.id.container);
img = (ImageView) findViewById(R.id.img);
findViewById(R.id.button).setOnClickListener(this);

ObjectAnimator animator = ObjectAnimator.ofInt(container, "backgroundColor", 0xFFFF0000, 0xFFFF00FF);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(img, "translationX", 0.0f, 200.0f, 0f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(img, "scaleX", 1.0f, 2.0f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(img, "rotationX", 0.0f, 90.0f, 0.0F);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(img, "alpha", 1.0f, 0.2f, 1.0F);
//组合动画方式1
set = new AnimatorSet();
set.play(animator)
.with(animator1)
.after(animator2)
.after(animator3)
.before(animator4);
set.setDuration(5000);
}

@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.button:
set.start();
break;
}
}


(2)使用AnimatorSet类中的playTogether(Animator…
items)方法实现多个动画同时执行的效果,如下:

set.playTogether(animator,animator1,animator2,animator3,animator4);


说明,其实查看它的源码发现,使用了上述的play、和with方法:
AnimatorSet#playTogether:

public void playTogether(Animator... items) {
if (items != null) {
Builder builder = play(items[0]);
for (int i = 1; i < items.length; ++i) {
builder.with(items[i]);
}
}
}


效果:





2 使用PropertyValuesHolder

在ObjectAnimator.ofPropertyValuesHolder(Object target, PropertyValuesHolder… values)方法里面,它的第三个参数接收一个PropertyValuesHolder参数,这个参数代表一个属性值集合,我们可以传入多个属性及其变化值范围,让这些属性同时变化,从而就实现了组合动画。
示例:

PropertyValuesHolder valuesHolder = PropertyValuesHolder.ofFloat("translationX", 0.0f, 300.0f);
PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.5f);
PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat("rotationX", 0.0f, 90.0f, 0.0F); PropertyValuesHolder valuesHolder3 = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.3f, 1.0F);
objectAnimator = ObjectAnimator.ofPropertyValuesHolder(img, valuesHolder, valuesHolder1, valuesHolder2, valuesHolder3);
objectAnimator.setDuration(2000).start();


说明,从上面这个例子中就可以很容易的看出它的用法了。下面我们来看看PropertyValuesHolder,它提供了四种类型的值Int,Float,Object,Keyframe。

public static PropertyValuesHolder ofInt(String propertyName, int... values)

public static PropertyValuesHolder ofInt(Property<?, Integer> property, int... values)

public static PropertyValuesHolder ofFloat(String propertyName, float... values)

public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values)

public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,Object... values)

public static <V> PropertyValuesHolder ofObject(Property property, TypeEvaluator<V> evaluator, V... values)

public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values)

public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values)


参数分析:

(1)target:ObjectAnimator作用的对象,即要被设置动画的对象
(2)propertyName:对象target的属性,这个属性值将在values范围内就行逐渐变化,以现实动画效果
(3)values:属性propertyName值变化范围

(4)TypeEvaluator:类型估值器,在《 Android属性动画之ValueAnimator》文章中有。
(5)PropertyValuesHolder:用来保存属性信息和这个属性的值,在《 Android属性动画之ValueAnimator》文章中有。

(6)Property:要使用一个类继承Property,进一步实现获取与设置propertyName的get、set方法,上文说过了

(7)Keyframe:保存相应的动画的触发时间和属性值,详见《 Android属性动画之ValueAnimator》。

3 使用ViewPropertyAnimator

先来介绍几个函数:

public abstract ViewPropertyAnimator setDuration(long duration);
设置持续时间

public abstract long getDuration();
得到持续时间

public abstract long getStartDelay();
得到开始延迟

public abstract ViewPropertyAnimator setStartDelay(long startDelay);
设置开始延迟

public abstract ViewPropertyAnimator setInterpolator(/*Time*/Interpolator interpolator);
设置插值器

public abstract ViewPropertyAnimator setListener(Animator.AnimatorListener listener);
设置监听器

public abstract void start();
开始动画

public abstract void cancel();
取消动画

public abstract ViewPropertyAnimator x(float value);
对属性x执行动画

public abstract ViewPropertyAnimator xBy(float value);
对属性x执行动画

public abstract ViewPropertyAnimator y(float value);
对属性y执行动画

public abstract ViewPropertyAnimator yBy(float value);
对属性y执行动画

public abstract ViewPropertyAnimator rotation(float value);
对属性rotation执行动画

public abstract ViewPropertyAnimator rotationBy(float value);
对属性rotation执行动画

public abstract ViewPropertyAnimator rotationX(float value);
对属性rotationX执行动画

public abstract ViewPropertyAnimator rotationXBy(float value);
对属性rotationX执行动画

public abstract ViewPropertyAnimator rotationY(float value);
对属性rotationY执行动画

public abstract ViewPropertyAnimator rotationYBy(float value);
对属性rotationY执行动画

public abstract ViewPropertyAnimator translationX(float value);
对属性translationX执行动画

public abstract ViewPropertyAnimator translationXBy(float value);
对属性translationX执行动画

public abstract ViewPropertyAnimator translationY(float value);
对属性translationY执行动画

public abstract ViewPropertyAnimator translationYBy(float value);
对属性translationY执行动画

public abstract ViewPropertyAnimator scaleX(float value);
对属性scaleX执行动画

public abstract ViewPropertyAnimator scaleXBy(float value);
对属性scaleX执行动画

public abstract ViewPropertyAnimator scaleY(float value);
对属性scaleY执行动画

public abstract ViewPropertyAnimator scaleYBy(float value);
对属性scaleY执行动画

public abstract ViewPropertyAnimator alpha(float value);
对属性alpha执行动画

public abstract ViewPropertyAnimator alphaBy(float value);
对属性alpha执行动画


看到这,发现怎么没有见到它的构造函数,去ViewPropertyAnimator中寻找也没有发现可以获取该对象实例public类型的函数,那么它是怎么用的呢?从字面上看,它和view的动画有关那么我们想要的函数会不会在view中,去view中一番查找下来,果真如此,如下:
VIew#animate:

public ViewPropertyAnimator animate() {
if (mAnimator == null) {
mAnimator = new ViewPropertyAnimator(this);
}
return mAnimator;
}


示例:

ViewPropertyAnimator viewPropertyAnimator = img.animate();
viewPropertyAnimator.translationX(200).scaleX(2).setDuration(2000).start();


五 总结

1 ObjectAnimator作用在一个对象,并且需要指出需要实现动画的具体属性,而这个属性必须有setXxx、getXxx方法,如果没有的话按照下面的方法加以解决:

a:给你的对象加上get和set方法,如果你有权限的话

b:用一个类来包装原始对象,间接为其提供get和set方法

c:采用ValueAnimator,监听动画过程,自己实现属性的改变

2 AnimatorSet用来实现组合动画,它可以组合N个ValueAnimator或ObjectAnimator,而组合动画的组合方式有三种:

a:使用AnimatorSet

b:使用PropertyValueHolder

c:使用ViewPropertyAnimator

参考:
http://blog.csdn.net/zhaoshecsdn/article/details/46673821
http://www.cnblogs.com/angeldevil/archive/2011/12/02/2271096.html
http://blog.csdn.net/hp910315/article/details/49157505
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐