文章目录
- 属性动画
- ValueAnimator
- ValueAnimator.ofInt
- ValueAnimator.ofArgb:
- Evaluator
- ValueAnimator.ofObject
- ValueAnimator.ofPropertyValuesHolder
- ObjectAnimator
- AnimatorSet
- animatorSet.playTogether()
- animatorSet.playSequentially()
- animatorSet.play().with().before().after()
属性动画
由于补间动画的不足,Android又引入了属性动画,直接改变对象的属性实现动画效果
补间动画和属性动画的区别:
命名的区别:
- 补间动画是xxxxAnimation
- 属性动画是xxxxAnimator
动画种类:
- 补间动画只有平移、缩放、旋转、透明度动画
- 属性动画可以对所有属性变化实现动画
动画状态:
- 补间动画是伪动画,比如点击事件只能在原位置触发
- 属性动画的当前状态,也是对象的真实状态
ValueAnimator
ValueAnimator.ofInt
我们简单的实现个动画例子:
animator1Tv=findViewById(R.id.animator1Tv);
ValueAnimator animator1=ValueAnimator.ofInt(0,100);
animator1.setDuration(2000);
animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
animator1Tv.setTranslationY((int) animation.getAnimatedValue());
}
});
findViewById(R.id.startTv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator1.start();
}
});
我们使用:
ValueAnimator animator1=ValueAnimator.ofInt(0,100)
实现了一个从0到100的数值变化过程,再将变化过程中的值设置给textview.setTranslationY()改变textview的位置实现动画效果。
可以看出,ValueAnimator本身并不是对View操作,而是对值操作,是值之间的变化过程
除了ValueAnimator.ofInt()直接构建ValueAnimator对象外,我们还有:
- ValueAnimator.ofFloat()
- ValueAnimator.ofArgb()
- ValueAnimator.ofObject()
- ValueAnimator.ofPropertyValuesHolder()
除了直接使用上面的静态方法构建ValueAnimator对象外,我们也可以直接new对象实现,比如上面的ofInt()可以写成:
ValueAnimator va=new ValueAnimator();
va.setIntValue(0,100)
他们之间的关系我整理如下图:
几个方法之间是有关系的,比如,我们定义一个动画可以有这四种不同的方式:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_value_animator);
animator1Tv=findViewById(R.id.animator1Tv);
animator2Tv=findViewById(R.id.animator2Tv);
animator3Tv=findViewById(R.id.animator3Tv);
animator4Tv=findViewById(R.id.animator4Tv);
final ValueAnimator animator1=ValueAnimator.ofInt(0,100);
final ValueAnimator animator2=new ValueAnimator();
animator2.setIntValues(0,100);
final ValueAnimator animator3=ValueAnimator.ofObject(new IntEvaluator(),0,100);
final ValueAnimator animator4=ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder.ofInt("",0,100));
animator1.addUpdateListener(new AnimatorListener(0));
animator2.addUpdateListener(new AnimatorListener(1));
animator3.addUpdateListener(new AnimatorListener(2));
animator4.addUpdateListener(new AnimatorListener(3));
animator1.setDuration(2000);
animator2.setDuration(2000);
animator3.setDuration(2000);
animator4.setDuration(2000);
findViewById(R.id.startTv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator1.start();
animator2.start();
animator3.start();
animator4.start();
}
});
}
public class AnimatorListener implements ValueAnimator.AnimatorUpdateListener{
private int index;
public AnimatorListener(int index){
this.index=index;
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value= (int) animation.getAnimatedValue();
switch (index){
case 0:
animator1Tv.setTranslationY(value);
break;
case 1:
animator2Tv.setTranslationY(value);
break;
case 2:
animator3Tv.setTranslationY(value);
break;
case 3:
animator4Tv.setTranslationY(value);
break;
}
}
}
可以看到,四种方式构建的动画效果是一样的。
ValueAnimator.ofInt()是对int值变化
ValueAnimator.ofFloat()是对float值变化
ValueAnimator.ofArgb() 对颜色的变化
ValueAnimator.ofArgb:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_value_animator);
textView = findViewById(R.id.textView);
final ValueAnimator animator = ValueAnimator.ofArgb(0xffff0000, 0xff0000ff);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
textView.setBackgroundColor((int) animation.getAnimatedValue());
}
});
animator.setDuration(5000);
findViewById(R.id.startTv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator.start();
}
});
}
TextView的背景色从0xffff0000(红色)变化成0xff0000ff(蓝色),我们再看看ofArgb()方法:
public static ValueAnimator ofArgb(int... values) {
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(values);
anim.setEvaluator(ArgbEvaluator.getInstance());
return anim;
}
可以看到,ofArgb()也是调用的va.setIntValues()方法,那它是如何实现颜色的渐变呢?ofInt()纯数值我们还可以蒙一下是数值递增什么的,这个颜色值的变化规则是什么?
Evaluator
ArgbEvaluator是如何实现颜色的渐变效果的?
public class ArgbEvaluator implements TypeEvaluator {
private static final ArgbEvaluator sInstance = new ArgbEvaluator();
public static ArgbEvaluator getInstance() {
return sInstance;
}
public Object evaluate(float fraction, Object startValue, Object endValue) {
//将startValue(0xffff0000)十六进制转成int
//int整形有32位,0xffff0000(11111111 11111111 00000000 00000000)
int startInt = (Integer) startValue;
//右移24位,(00000000 00000000 00000000 11111111)
//& 0xff 后得:(00000000 00000000 00000000 11111111)
//&操作符,同位都是1,即为1
//取出Alpha通道的值
float startA = ((startInt >> 24) & 0xff) / 255.0f;
//取出R通道的值
float startR = ((startInt >> 16) & 0xff) / 255.0f;
//取出G通道的值
float startG = ((startInt >> 8) & 0xff) / 255.0f;
//取出B通道的值
float startB = ( startInt & 0xff) / 255.0f;
int endInt = (Integer) endValue;
float endA = ((endInt >> 24) & 0xff) / 255.0f;
float endR = ((endInt >> 16) & 0xff) / 255.0f;
float endG = ((endInt >> 8) & 0xff) / 255.0f;
float endB = ( endInt & 0xff) / 255.0f;
// convert from sRGB to linear
startR = (float) Math.pow(startR, 2.2);
startG = (float) Math.pow(startG, 2.2);
startB = (float) Math.pow(startB, 2.2);
endR = (float) Math.pow(endR, 2.2);
endG = (float) Math.pow(endG, 2.2);
endB = (float) Math.pow(endB, 2.2);
//基于fraction(Intepolator中的t)动画当前进度计算出新的argb
float a = startA + fraction * (endA - startA);
float r = startR + fraction * (endR - startR);
float g = startG + fraction * (endG - startG);
float b = startB + fraction * (endB - startB);
// convert back to sRGB in the [0..255] range
a = a * 255.0f;
r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;
//对计算出来的argb进行位操作放到对应的位置合成新的int颜色值
return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
}
}
可以看到ArgbEvaluator只实现了一个方法evaluate()并根据fraction当前进度计算出新的颜色值,这就是颜色变化的计算规则了。
既然Evaluator和Interpolator都可以对动画效果进行控制,那么他们的区别是啥?
在LinearInterpolator中,getInterpolation返回的是View在路程中的比例,比如返回0.5f,那就是表示view运动了一半:
//LinearInterpolator.java
public float getInterpolation(float input) {
return input;
}
那它这个比例是如何换算成具体数值给view使用的呢?
我们拿TranslateAnimation平移动画的实现来看看:
//TranslateAnimation.java
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float dx = mFromXDelta;
float dy = mFromYDelta;
if (mFromXDelta != mToXDelta) {
dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
}
if (mFromYDelta != mToYDelta) {
dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
}
t.getMatrix().setTranslate(dx, dy);
}
参数interpolatedTime就是getInterpolation返回值(路程比例)
dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
用总路程(end-start)*interpolatedTime(路程比例),就可以得出当前走了多少路程,再加上start就知道从start开始算,走了多远的距离。这就是最终运用给view的数值。
我们再来看看,在ValueAnimator中又是如何处理Interpolator的具体数值转化的
//ValueAnimator.java
@CallSuper
@UnsupportedAppUsage
void animateValue(float fraction) {
//根据当前时间进度fraction[0,1],求得路程进度fraction[可大于1,也可小于0,即view可超出终点和起点]
fraction = mInterpolator.getInterpolation(fraction);
mCurrentFraction = fraction;
//mValues为封装的ProperyValuesHolder数组,封装了如ofInt(0,100)两个值
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//根据封装的每个参数[0,100]和进度fraction,计算出具体值
mValues[i].calculateValue(fraction);
}
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
//最终通过我们设置的动画监听器用animation.getAnimatedValue()获取值给view使用
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
}
//PropertyValuesHolder.java
void calculateValue(float fraction) {
Object value = mKeyframes.getValue(fraction);
mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
}
//FloatKeyframeSet.java
@Override
public Object getValue(float fraction) {
return getFloatValue(fraction);
}
@Override
public float getFloatValue(float fraction) {
//当位置进度小于起点位置
if (fraction <= 0f) {
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1);
float prevValue = prevKeyframe.getFloatValue();
float nextValue = nextKeyframe.getFloatValue();
float prevFraction = prevKeyframe.getFraction();
float nextFraction = nextKeyframe.getFraction();
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
if (interpolator != null) {
fraction = interpolator.getInterpolation(fraction);
}
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
return mEvaluator == null ?
prevValue + intervalFraction * (nextValue - prevValue) :
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
floatValue();
//当位置进度大于终点位置
} else if (fraction >= 1f) {
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2);
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1);
float prevValue = prevKeyframe.getFloatValue();
float nextValue = nextKeyframe.getFloatValue();
float prevFraction = prevKeyframe.getFraction();
float nextFraction = nextKeyframe.getFraction();
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
if (interpolator != null) {
fraction = interpolator.getInterpolation(fraction);
}
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
return mEvaluator == null ?
prevValue + intervalFraction * (nextValue - prevValue) :
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
floatValue();
}
//当位置进度在[0,1]之间
FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
//遍历每一关键帧
for (int i = 1; i < mNumKeyframes; ++i) {
FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
if (fraction < nextKeyframe.getFraction()) {
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
//算出当前帧在前一帧和后一帧之间的比例
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
float prevValue = prevKeyframe.getFloatValue();
float nextValue = nextKeyframe.getFloatValue();
// Apply interpolator on the proportional duration.
//根据当前进度,换算出我们设置的Interpolator反应出的新的进度比例。
if (interpolator != null) {
intervalFraction = interpolator.getInterpolation(intervalFraction);
}
//如果设置了Interpolator,最终会影响值得计算
return mEvaluator == null ?
prevValue + intervalFraction * (nextValue - prevValue) :
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
floatValue();
}
prevKeyframe = nextKeyframe;
}
// shouldn't get here
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
}
我们可以看到最终的一个算法
return mEvaluator == null ?prevValue + intervalFraction * (nextValue - prevValue) :
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).floatValue();
- 当Evaluator==null时,跟我们前面TranslateAnimation的算法一致
- 当Evaluator!=null时,直接调用了Evaluator.evaluate()计算具体数值
总结:
Interpolator返回的计算值是动画当前位置所在总路程的比例,帧动画(如TranslateAnimation)中,实现了根据这个比例算出具体数值应用给view实现动画
Evaluator返回的计算值就是根据动画当前位置所在总路程的比例,算出的具体数值给view实现动画(也就是TranslateAnimation中换算具体数值的操作)
也就是说,在帧动画中,已经帮我们实现了具体值的换算,而在ValueAnimator中,需要我们自己实现Evaluator来实现值的换算
有朋友会有疑问了,在ofInt(),ofFloat()中,我们并没有设置Evaluator来换算值啊?经过上面的ofArgb(),我们知道,内部帮我们设置了一个ArgbEvaluator,那ofInt(),ofFloat()肯定也是内容帮我们设置好了对应的Evaluator了。
//PropertyValuesHolder.java
void init() {
if (mEvaluator == null) {
// We already handle int and float automatically, but not their Object
// equivalents
mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
(mValueType == Float.class) ? sFloatEvaluator :
null;
}
if (mEvaluator != null) {
// KeyframeSet knows how to evaluate the common types - only give it a custom
// evaluator if one has been set on this class
mKeyframes.setEvaluator(mEvaluator);
}
}
查看源码,底层确实帮我们设置好了对应Evaluator了。
private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
public class FloatEvaluator implements TypeEvaluator<Number> {
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
}
可以看到
startInt + fraction * (endValue - startInt)
是一种常用的值换算算法。
ofInt(),ofFloat(),ofArgb()都帮我们实现了Evaluator来实现值的换算,那ofObject()该怎么办?当然要我们自己自定义Evaluator来实现啦。
ValueAnimator.ofObject
我们举个例子,有一只猫,出生时有10根毛发,成年时有1000根毛发,求这只猫从出生到成年毛发增长的数值变化过程。
我们定义一个类Cat.class:
public class Cat{
//当前猫的状态(0:出生,1:成年)
private String status;
//毛发的数量
private int hair;
public Cat(String status, int hair) {
this.status = status;
this.hair = hair;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getHair() {
return hair;
}
public void setHair(int hair) {
this.hair = hair;
}
}
然后我们使用ValueAnimator.ofObject()设置两个状态的猫,并通过AccelerateInterpolator实现加速的一种变化效果
ValueAnimator animator = ValueAnimator.ofObject(new MyEvaluator(),new Cat("幼崽",10),new Cat("成年",1000));
animator.setInterpolator(new AccelerateInterpolator());
接着,我们自定义MyEvaluator实现具体毛发数量值的计算:
public class MyEvaluator implements TypeEvaluator<Cat> {
@Override
public Cat evaluate(float fraction, Cat startCat, Cat endCat) {
return new Cat("长毛中", (int) (startCat.getHair()+(endCat.getHair()-startCat.getHair())*fraction));
}
}
所有代码:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_value_animator);
textView = findViewById(R.id.textView);
final ValueAnimator animator = ValueAnimator.ofObject(new MyEvaluator(),new Cat("幼崽",10),new Cat("成年",1000));
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Cat cat= (Cat) animation.getAnimatedValue();
textView.setText(cat.getStatus()+":"+cat.getHair());
}
});
animator.setDuration(5000);
findViewById(R.id.startTv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator.start();
}
});
}
public class Cat{
//当前猫的状态
private String status;
//毛发的数量
private int hair;
public Cat(String status, int hair) {
this.status = status;
this.hair = hair;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getHair() {
return hair;
}
public void setHair(int hair) {
this.hair = hair;
}
}
public class MyEvaluator implements TypeEvaluator<Cat> {
@Override
public Cat evaluate(float fraction, Cat startCat, Cat endCat) {
return new Cat("长毛中", (int) (startCat.getHair()+(endCat.getHair()-startCat.getHair())*fraction));
}
}
ValueAnimator.ofPropertyValuesHolder
根据一开始我们给出的思维导图我们知道,ofInt()…ofPropertyValuesHoler()最终都是调用的setValues()方法
//ValueAnimator.java
public void setValues(PropertyValuesHolder... values) {
int numValues = values.length;
mValues = values;
mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
for (int i = 0; i < numValues; ++i) {
PropertyValuesHolder valuesHolder = values[i];
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
比如ofInt()的setIntValues():
//ValueAnimator.java
public void setIntValues(int... values) {
if (values == null || values.length == 0) {
return;
}
if (mValues == null || mValues.length == 0) {
setValues(PropertyValuesHolder.ofInt("", values));
} else {
PropertyValuesHolder valuesHolder = mValues[0];
valuesHolder.setIntValues(values);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
所以我们的ofInt还可以这样实现:
final ValueAnimator animator = ValueAnimator.ofInt(0,100);
final ValueAnimator animator=ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder.ofInt("",0,100));
PropertyValuesHolder
根据名字我们分析,这个东西保存了一个属性名(可以为空字符串)以及属性值values,我们猜测,这个对象实现了值values的变化过程并把变化的值设置给了这个名称的属性,从而实现了属性动画
我们来看看ProeryValuesHolder提供了哪些构造方法:
那我们猜测,可以通过ofInt(“Rotation”,0,100)实现对View旋转100度的动画
看个例子:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_value_animator);
textView = findViewById(R.id.textView);
final ValueAnimator animator=ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder.ofFloat("Rotation",0,100));
animator.setTarget(textView);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value= (int) animation.getAnimatedValue();
textView.setText(value+"");
}
});
animator.setDuration(5000);
findViewById(R.id.startTv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator.start();
}
});
}
通过AnimatorUpdateListener我们知道,值确实变化了,但并没有旋转,难道是 animator.setTarget(textView);没起作用,导致值没有绑定到target的对应属性上?
//Animator.java
public void setTarget(@Nullable Object target) {
}
通过源码,我们知道这个是抽象类Animator的方法,然而我们在它的实现类ValueAnimator中并没有发现重写了这个方法,也就是说,ValueAnimator不能设置Target并绑定属性,进一步明确,ValueAnimator只是对值的一个操作。
既然ValueAnimator不行,那我们换它的继承类ObjectAnimator试试:
ObjectAnimator
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_value_animator);
textView = findViewById(R.id.textView);
final ValueAnimator animator= ObjectAnimator.ofPropertyValuesHolder(textView,PropertyValuesHolder.ofFloat("Rotation",0,100));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value= (float) animation.getAnimatedValue();
textView.setText(value+"");
}
});
animator.setDuration(5000);
findViewById(R.id.startTv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator.start();
}
});
}
所以,要绑定属性进行动画:
- 要么用ValueAnimator,在onAnimationUpdate回调函数中自己根据变化的值设置给view的属性实现动画
- 要么用ObjectAnimator,设置对象和对应属性,即可自动实现改变对应属性实现动画
ObjectAnimator继承至ValueAnimator,所以用法跟ValueAnimator是一样的,不同的是多了对象和属性的绑定,绑定属性的前提是对象中必须要有对应的set方法,比如上面的属性"Rotation"能起作用,是因为TextView中有setRotation(float rotation)方法,注意参数类型是float,所以要用ofFloat(),用ofInt()是不行的。
用法没啥难度,就不细讲了,最后就是补一下关键帧的一个用法:
PropertyValuesHolder.ofKeyframe("Rotation", Keyframe.ofFloat(0,0),Keyframe.ofFloat(0.5f,90),Keyframe.ofFloat(1f,0))
意思是,我定义三个关键帧:
- 第一个关键帧为进度为0时,角度为0
- 第一个关键帧为进度为0.5时,角度为90
- 第一个关键帧为进度为1时,角度为0
也就是定义了一个从0旋转到90度再旋转到0度的动画
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_value_animator);
textView = findViewById(R.id.textView);
final ValueAnimator animator= ObjectAnimator.ofPropertyValuesHolder(textView,PropertyValuesHolder
.ofKeyframe("Rotation", Keyframe.ofFloat(0,0),Keyframe.ofFloat(0.5f,90),Keyframe.ofFloat(1f,0)));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value= (float) animation.getAnimatedValue();
textView.setText(value+"");
}
});
animator.setDuration(5000);
findViewById(R.id.startTv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator.start();
}
});
}
AnimatorSet
AnimatorSet就是几个动画的集合,用的也比较多,我们了解一下
animatorSet.playTogether()
几个动画同时进行
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_value_animator);
textView = findViewById(R.id.textView);
ObjectAnimator rotation = ObjectAnimator.ofFloat(textView, "Rotation", 0, 360);
ObjectAnimator scaleX = ObjectAnimator.ofFloat(textView, "ScaleX", 1, 2, 1);
ObjectAnimator translationX = ObjectAnimator.ofFloat(textView, "TranslationX", 0, 100, 0, -100, 0);
final AnimatorSet animatorSet=new AnimatorSet();
animatorSet.setDuration(3000);
animatorSet.playTogether(rotation,scaleX,translationX);
findViewById(R.id.startTv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animatorSet.start();
}
});
}
animatorSet.playSequentially()
几个动画按序进行
那如果我有的想一起进行,有的想按序进行怎么办呢?
animatorSet.play().with().before().after()
按需组合顺序
animatorSet.play(rotation).with(scaleX).before(translationX);