ObjectAnimator,通过设置改变对象的属性来实现动画效果,常用的方法有这么几种,ofFloat()、ofInt()、ofObject()、ofArgb()、ofPropertyValuesHolder(),具体含义及使用我们在下面的实例中进行讲解。
使用ObjectAnimator也是可以轻松的实现平移、缩放、旋转、透明度这几种动画效果的,与补间动画的使用效果是一样的,那就先来看看这几种常用的动画是怎么实现的。
工程代码里就是一个ImageView控件和Activity,
1
2
3
4
5
6
|
|
1
2
3
4
5
6
|
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_object_animator);
head = (ImageView) findViewById(R.id.head);
}
|
我们这里就是对ImageView控件head实现动画效果,本质就是改变head的属性。
1.平移(translate)
1
|
// 平移 private void translateAnimation() { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head, "translationX", 0.0f, 350.0f, 0.0f); objectAnimator.setDuration(2000); objectAnimator.setRepeatCount(Animation.INFINITE); objectAnimator.setRepeatMode(Animation.RESTART); objectAnimator.start(); }
|
target:动画操作的对象,我们这里的操作对象就是ImageView控件head
propertyName:属性名称,这里的"translationX"属性值意思就是在水平方向移动,如果是"translationY"就是在垂直方向移动,下面讲到的其动画效果也是这个意思,这个属性值跟我们在xml文件中设置属性值得名称是一致的,比如
1
|
"android:translationY"
。
|
values:动画过渡值,过渡值可以有一个到N个,如果是一个值的话,就默认是这个动画过渡值的结束值,如果有N个值,动画就在这N个值之间过渡,如本例中有三个过渡值"0.0f, 350.0f, 0f",意思就是从当前位置向右滑到350的位置,再滑到位置0,即初始位置。
然后是动画的设置,
1
2
3
|
objectAnimator.setDuration(
2000
);
//动画的时间间隔
objectAnimator.setRepeatCount(Animation.INFINITE);
//重复次数
objectAnimator.setRepeatMode(Animation.RESTART);
//重复模式
|
最后start,动画就开始执行了
1
|
objectAnimator.start();
|
2.缩放(scale)
1
2
3
4
5
6
7
8
|
// 缩放
private
void
scaleXAnimation() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head,
"scaleX"
,
1
.0f,
1
.5f);
objectAnimator.setDuration(
2000
);
objectAnimator.setRepeatCount(Animation.INFINITE);
objectAnimator.setRepeatMode(Animation.RESTART);
objectAnimator.start();
}
|
1
|
3
.旋转(rotate)
|
1
2
3
4
5
6
7
8
|
// 旋转
private
void
rotateAnimation() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head,
"rotationX"
,
0
.0f,
90
.0f,
0
.0F);
objectAnimator.setDuration(
2000
);
objectAnimator.setRepeatCount(Animation.INFINITE);
objectAnimator.setRepeatMode(Animation.RESTART);
objectAnimator.start();
}
|
1
|
4
.透明度(alpha)
|
1
2
3
4
5
6
7
8
|
// 透明度
private
void
alphaAnimation() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head,
"alpha"
,
1
.0f,
0
.3f,
1
.0F);
objectAnimator.setDuration(
2000
);
objectAnimator.setRepeatCount(Animation.INFINITE);
objectAnimator.setRepeatMode(Animation.RESTART);
objectAnimator.start();
}
|
可能我们也注意到了,在缩放效果的实例中,图片被放大后就保持当前的状态,没有变为初始的样子,这是因为我们在设置过渡值是最终的状态是1.5f,就放大到1.5倍,并没有让它回到原来的状态,从这点就可以看出,属性动画是真真切切的可以改变控件的属性的,这是与补间动画的最大不同,补间动画在动画结束后都将回到初始状态。所以说,属性动画的使用就显得更加的灵活。至于上面的其他三个实例,最终回到初始状态,是因为我们在设过渡值的时候最终状态设定的就是初始状态。
刚才我们讨论了几种常见的动画效果,如果仅有这些功能的话,那就与补间动画没有太大的区别。其实,属性动画还可以设置其他的属性值。ObjectAnimator的ofObject方法,就是用来对任意对象进行动画设置的,如字体颜色,直接看实例
1
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
int
startColor =
0xffff0000
;
int
endColor =
0xff00ff00
;
ObjectAnimator objectAnimator4 = ObjectAnimator.ofObject(txt,
"textColor"
,
new
TypeEvaluator() {
@Override
public
Object evaluate(
float
fraction, Object startValue, Object endValue) {
int
startInt = (Integer) startValue;
int
startA = (startInt >>
24
) &
0xff
;
int
startR = (startInt >>
16
) &
0xff
;
int
startG = (startInt >>
8
) &
0xff
;
int
startB = startInt &
0xff
;
int
endInt = (Integer) endValue;
int
endA = (endInt >>
24
) &
0xff
;
int
endR = (endInt >>
16
) &
0xff
;
int
endG = (endInt >>
8
) &
0xff
;
int
endB = endInt &
0xff
;
return
(
int
)((startA + (
int
)(fraction * (endA - startA))) <<
24
) |
(
int
)((startR + (
int
)(fraction * (endR - startR))) <<
16
) |
(
int
)((startG + (
int
)(fraction * (endG - startG))) <<
8
) |
(
int
)((startB + (
int
)(fraction * (endB - startB))));
}
}, startColor, endColor);
objectAnimator4.setDuration(
3000
);
objectAnimator4.start();
|
ofObject方法的原型
1
|
public
static
ObjectAnimator ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values)
|
1
2
|
ObjectAnimator objectAnimator2 = ObjectAnimator.ofArgb(txt,
"textColor"
,
0x000
,
0x00FF00
);
objectAnimator2.start();
|
1.setInterpolator():设置动画插值
控制动画的变化速率,系统中定义了好几种Interpolator:
LinearInterpolator--均匀的速率改变AccelerateDecelerateInterpolator--先加速后减速
AccelerateInterpolator--加速
DecelerateInterpolator--减速
CycleInterpolator--动画循环播放特定的次数,速率改变沿着正弦曲线3.setRepeatCount():设置动画重复次数
大于0的值就代表重复几次,如果需要无限循环,设为-1,上面的Animation.INFINITE是系统给的常量,值为-1,代表无限循环,我们建议使用这个常量,如果设为0呢?也是执行一次。
4.setRepeatMode():设置动画重复模式
5.setStartDelay():设置动画延时操作,也是以毫秒为单位(ms)
6.setTarget():设置动画的对象
操作对象,上面的例子中将动画对象通过ofXXX方传递,如果需要改变动画对象,但动画效果不变,我们可以使用该方法来设置。
1
|
objectAnimator.setTarget(txt);
//将动画对象head变为txt
|
1
2
3
4
|
after(Animator anim)--将现有动画插入到传入的动画之后执行
after(
long
delay)--将现有动画延迟指定毫秒后执行
before(Animator anim)--将现有动画插入到传入的动画之前执行
with(Animator anim)--将现有动画和传入的动画同时执行
|
1
|
|
1
|
playSequentially(Animator... items)--依次执行
|
1
2
3
4
5
6
7
8
9
|
private
void
multiAnimation() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(head,
"scaleX"
,
1
.0f,
2
.5f,
1
.0f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(head,
"scaleY"
,
1
.0f,
2
.5f,
1
.0f);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(head,
"rotationX"
,
0
.0f,
90
.0f,
0
.0F);
AnimatorSet animatorSet =
new
AnimatorSet();
animatorSet.play(objectAnimator1).with(objectAnimator2).with(objectAnimator3);
animatorSet.setDuration(
2000
);
animatorSet.start();
}
|
让动画同时执行除了使用with方法外,还可以用playTogether方法,
1
|
animatorSet.playTogether(objectAnimator1, objectAnimator2, objectAnimator3);
|
1
|
这种方式只能多个动画一起执行,不同设置先后顺序。
|
1
2
3
4
5
6
7
8
|
private
void
multiAnimation2() {
PropertyValuesHolder valuesHolder = PropertyValuesHolder.ofFloat(
"scaleX"
,
1
.0f,
2
.5f,
1
.0f);
PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofFloat(
"scaleY"
,
1
.0f,
2
.5f,
1
.0f);
PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat(
"rotationX"
,
0
.0f,
90
.0f,
0
.0F);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(head, valuesHolder, valuesHolder1, valuesHolder2);
objectAnimator.setDuration(
2000
);
objectAnimator.start();
}
|
1
2
3
4
5
6
7
8
|
private
void
viewPropertyAnimator() {
ViewPropertyAnimator animator = head.animate();
animator.translationX(
200
)
.scaleX(
2
)
.scaleY(
2
)
.setDuration(
2000
)
.start();
}
|
一般情况下,我们除了需要动画效果外,还需要对动画的执行过程进行监听,在执行前、执行结束后或者执行过程中,做出相应的处理,比如动画结束后,请求网络数据。系统给我们提供几种监听接口,来监听动画的各个状态,如AnimatorListener,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
private
void
animationListener() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head,
"translationX"
,
0
.0f,
350
.0f, 0f);
objectAnimator.setDuration(
2000
);
objectAnimator.addListener(
new
Animator.AnimatorListener() {
@Override
public
void
onAnimationStart(Animator animation) {
Log.d(
"dingfeng"
,
"onAnimationStart......"
);
}
@Override
public
void
onAnimationEnd(Animator animation) {
Log.d(
"dingfeng"
,
"onAnimationEnd......"
);
}
@Override
public
void
onAnimationCancel(Animator animation) {
Log.d(
"dingfeng"
,
"onAnimationCancel......"
);
}
@Override
public
void
onAnimationRepeat(Animator animation) {
Log.d(
"dingfeng"
,
"onAnimationRepeat......"
);
}
});
objectAnimator.start();
}
|
可以根据不同需求来实现接口里面的四个方法,可以根据需要做相应的处理。但有时候你会觉得我不需要监听动画的四种状态,我只需要监听动画结束时候的状态,使用上面的方法就会感觉代码臃肿了,不过没关系,Android系统给我们提供了一个更好用的方法,
1
2
3
4
5
6
7
8
9
10
11
12
|
private
void
animationListener2() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head,
"translationX"
,
0
.0f,
350
.0f, 0f);
objectAnimator.setDuration(
2000
);
objectAnimator.addListener(
new
AnimatorListenerAdapter() {
@Override
public
void
onAnimationEnd(Animator animation) {
super
.onAnimationEnd(animation);
Log.d(
"dingfeng"
,
"onAnimationEnd......"
);
}
});
objectAnimator.start();
}
|
1
2
3
|
可以看出,我们使用了AnimatorListenerAdapter动画接口适配器代替AnimatorListener接口。其实AnimatorListenerAdapter的源码只是一个实现了AnimatorListener接口的抽象类而已,
你需要监听哪种动画状态就重写哪种方法就可以了。
除此之外,AnimatorUpdateListener接口就可以读取到动画的每个更新值。
|
1
|
|
1
|
private
void
animationListener3() { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head,
"translationX"
,
0
.0f,
350
.0f, 0f); objectAnimator.setDuration(
2000
); objectAnimator.addUpdateListener(
new
ValueAnimator.AnimatorUpdateListener() {
@Override
public
void
onAnimationUpdate(ValueAnimator animation) {
float
value = (
float
)animation.getAnimatedValue(); Log.d(
"dingfeng"
,
"onAnimationUpdate......"
+value); } }); objectAnimator.start(); }
|
我们创建两个动画文件,一个是旋转动画,一个组合动画
1
2
|
|
1
2
3
4
5
6
7
8
9
|
|
1
2
3
4
|
head = (ImageView) findViewById(R.id.head);
Animator animator = AnimatorInflater.loadAnimator(
this
, R.animator.multi);
animator.setTarget(head);
animator.start();
|