1
2
3
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"alpha"
,
1
,
0
,
1
);
animator.setDuration(
2000
);
animator.start();
|
我们这里还是直接使用上一篇的框架代码;(当点击start anim时执行动画)从上面的代码中可以看到构造ObjectAnimator的方法非常简单:
1
|
public
static
ObjectAnimator ofFloat(Object target, String propertyName,
float
... values)
|
1
2
3
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"rotation"
,
0
,
180
,
0
);
animator.setDuration(
2000
);
animator.start();
|
从代码中可以看到,我们只需要改变ofFloat()的第二个参数的值就可以实现对应的动画;
那么问题来了,我们怎么知道第二个参数的值是啥呢?
1
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"rotation"
,
0
,
180
,
0
);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//1、透明度:alpha
public
void
setAlpha(
float
alpha)
//2、旋转度数:rotation、rotationX、rotationY
public
void
setRotation(
float
rotation)
public
void
setRotationX(
float
rotationX)
public
void
setRotationY(
float
rotationY)
//3、平移:translationX、translationY
public
void
setTranslationX(
float
translationX)
public
void
setTranslationY(
float
translationY)
//缩放:scaleX、scaleY
public
void
setScaleX(
float
scaleX)
public
void
setScaleY(
float
scaleY)
|
1
2
3
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"rotationX"
,
0
,
270
,
0
);
animator.setDuration(
2000
);
animator.start();
|
效果图如下:
1
2
3
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"rotationY"
,
0
,
180
,
0
);
animator.setDuration(
2000
);
animator.start();
|
效果图如下:
1
2
3
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"rotation"
,
0
,
270
,
0
);
animator.setDuration(
2000
);
animator.start();
|
1
2
3
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"translationX"
,
0
,
200
, -
200
,
0
);
animator.setDuration(
2000
);
animator.start();
|
所以,我们上面在构造动画时,指定的移动距离是(0, 200, -200,0),所以控件会从自身所有位置向右移动200像素,然后再移动到距离原点-200的位置,最后回到原点;
然后我们来看看setTranslateY的用法:
1
2
3
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"translationY"
,
0
,
200
, -
100
,
0
);
animator.setDuration(
2000
);
animator.start();
|
同样,移动位置的坐标也都是以当前控件所在位置为中心点的。所以对应的移动位置从原点移动向下移动200像素,然后再移动到向下到距原点200像素的位置,最后再回到(0,0)从效果图中很明显可以看出来。
从上面可以看出:每次移动距离的计算都是以原点为中心的;比如初始动画为ObjectAnimator.ofFloat(tv, “translationY”, 0, 200, -100,0)表示首先从0移动到正方向200的位置,然后再移动到负方向100的位置,最后移动到原点。
1
2
3
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"scaleX"
,
0
,
3
,
1
);
animator.setDuration(
2000
);
animator.start();
|
在效果图中,从0倍放大到3倍,然后再还原到1倍的原始状态。
然后再来看看setScaleY的用法
1
2
3
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"scaleY"
,
0
,
3
,
1
);
animator.setDuration(
2000
);
animator.start();
|
在这张图中,将ValueAnimator的动画流程与ObjectAnimator的动画流程做了个对比。
可以看到ObjectAnimator的动画流程中,也是首先通过加速器产生当前进度的百分比,然后再经过Evaluator生成对应百分比所对应的数字值。这两步与ValueAnimator是完全一样的,唯一不同的是最后一步,在ValueAnimator中,我们要通过添加监听器来监听当前数字值。而在ObjectAnimator中,则是先根据属性值拼装成对应的set函数的名字,比如这里的scaleY的拼装方法就是将属性的第一个字母强制大写后,与set拼接,所以就是setScaleY。然后通过反射找到对应控件的setScaleY(float scaleY)函数,将当前数字值做为setScaleY(float scale)的参数将其传入。
这里在找到控件的set函数以后,是通过反射来调用这个函数的,有关反射的使用大家可以参考《夯实JAVA基本之二 —— 反射(1):基本类周边信息获取》
这就是ObjectAnimator的流程,最后一步总结起来就是调用对应属性的set方法,将动画当前数字值做为参数传进去。
根据上面的流程,这里有几个注意事项:
(1)、拼接set函数的方法:上面我们也说了是首先是强制将属性的第一个字母大写,然后与set拼接,就是对应的set函数的名字。注意,只是强制将属性的第一个字母大写,后面的部分是保持不变的。反过来,如果我们的函数名命名为setScalePointX(float ),那我们在写属性时可以写成”scalePointX”或者写成“ScalePointX”都是可以的,即第一个字母大小写可以随意,但后面的部分必须与set方法后的大小写保持一致。
(2)、如何确定函数的参数类型:上面我们知道了如何找到对应的函数名,那对应的参数方法的参数类型如何确定呢?我们在讲ValueAnimator的时候说过,动画过程中产生的数字值与构造时传入的值类型是一样的。由于ObjectAnimator与ValueAnimator在插值器和Evaluator这两步是完全一样的,而当前动画数值的产生是在Evaluator这一步产生的,所以ObjectAnimator的动画中产生的数值类型也是与构造时的类型一样的。那么问题来了,像我们的构造方法。
1
|
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
"scaleY"
,
0
,
3
,
1
);
|
意思就是对应函数的指定参数类型没有找到。
(3)、调用set函数以后怎么办?从ObjectAnimator的流程可以看到,ObjectAnimator只负责把动画过程中的数值传到对应属性的set函数中就结束了,注意传给set函数以后就结束了!set函数就相当我们在ValueAnimator中添加的监听的作用,set函数中的对控件的操作还是需要我们自己来写的。
那我们来看看View中的setScaleY是怎么实现的吧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
* Sets the amount that the view is scaled in Y around the pivot point, as a proportion of
* the view's unscaled width. A value of 1 means that no scaling is applied.
*
* @param scaleY The scaling factor.
* @see #getPivotX()
* @see #getPivotY()
*
* @attr ref android.R.styleable#View_scaleY
*/
public
void
setScaleY(
float
scaleY) {
ensureTransformationInfo();
final
TransformationInfo info = mTransformationInfo;
if
(info.mScaleY != scaleY) {
invalidateParentCaches();
// Double-invalidation is necessary to capture view's old and new areas
invalidate(
false
);
info.mScaleY = scaleY;
info.mMatrixDirty =
true
;
mPrivateFlags |= DRAWN;
// force another invalidation with the new orientation
invalidate(
false
);
}
}
|
这个效果图与我们上篇自定义控件实现的效果差不多,这个控件中存在一个圆形,也是在动画时先将这个圆形放大,然后再将圆形还原。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
class
Point {
private
int
mRadius;
public
Point(
int
radius){
mRadius = radius;
}
public
int
getRadius() {
return
mRadius;
}
public
void
setRadius(
int
radius) {
mRadius = radius;
}
}
|
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
|
public
class
MyPointView
extends
View {
private
Point mPoint =
new
Point(
100
);
public
MyPointView(Context context, AttributeSet attrs) {
super
(context, attrs);
}
@Override
protected
void
onDraw(Canvas canvas) {
if
(mPoint !=
null
){
Paint paint =
new
Paint();
paint.setAntiAlias(
true
);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(
300
,
300
,mPoint.getRadius(),paint);
}
super
.onDraw(canvas);
}
void
setPointRadius(
int
radius){
mPoint.setRadius(radius);
invalidate();
}
}
|
1
2
3
4
|
void
setPointRadius(
int
radius){
mPoint.setRadius(radius);
invalidate();
}
|
1
2
3
4
5
6
7
8
9
10
11
|
@Override
protected
void
onDraw(Canvas canvas) {
if
(mPoint !=
null
){
Paint paint =
new
Paint();
paint.setAntiAlias(
true
);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(
300
,
300
,mPoint.getRadius(),paint);
}
super
.onDraw(canvas);
}
|
1
2
3
4
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class
MyActivity
extends
Activity {
private
Button btnStart;
private
MyPointView mPointView;
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnStart = (Button) findViewById(R.id.btn);
mPointView = (MyPointView)findViewById(R.id.pointview);
btnStart.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
doPointViewAnimation();
}
});
}
…………
}
|
1
2
3
4
5
|
private
void
doPointViewAnimation(){
ObjectAnimator animator = ObjectAnimator.ofInt(mPointView,
"pointRadius"
,
0
,
300
,
100
);
animator.setDuration(
2000
);
animator.start();
}
|
1
|
public
void
setBackgroundColor(
int
color);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public
class
ArgbEvaluator
implements
TypeEvaluator {
public
Object evaluate(
float
fraction, Object startValue, Object endValue) {
int
startInt = (Integer) startValue;
int
startA = (startInt >>
24
);
int
startR = (startInt >>
16
) &
0xff
;
int
startG = (startInt >>
8
) &
0xff
;
int
startB = startInt &
0xff
;
int
endInt = (Integer) endValue;
int
endA = (endInt >>
24
);
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))));
}
}
|
1
2
3
4
|
ObjectAnimator animator = ObjectAnimator.ofInt(tv,
"BackgroundColor"
,
0xffff00ff
,
0xffffff00
,
0xffff00ff
);
animator.setDuration(
8000
);
animator.setEvaluator(
new
ArgbEvaluator());
animator.start();
|
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
|
/**
* 设置动画时长,单位是毫秒
*/
ValueAnimator setDuration(
long
duration)
/**
* 获取ValueAnimator在运动时,当前运动点的值
*/
Object getAnimatedValue();
/**
* 开始动画
*/
void
start()
/**
* 设置循环次数,设置为INFINITE表示无限循环
*/
void
setRepeatCount(
int
value)
/**
* 设置循环模式
* value取值有RESTART,REVERSE,
*/
void
setRepeatMode(
int
value)
/**
* 取消动画
*/
void
cancel()
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* 监听器一:监听动画变化时的实时值
*/
public
static
interface
AnimatorUpdateListener {
void
onAnimationUpdate(ValueAnimator animation);
}
//添加方法为:public void addUpdateListener(AnimatorUpdateListener listener)
/**
* 监听器二:监听动画变化时四个状态
*/
public
static
interface
AnimatorListener {
void
onAnimationStart(Animator animation);
void
onAnimationEnd(Animator animation);
void
onAnimationCancel(Animator animation);
void
onAnimationRepeat(Animator animation);
}
//添加方法为:public void addListener(AnimatorListener listener)
|
1
2
3
4
5
6
7
8
|
/**
* 设置插值器
*/
public
void
setInterpolator(TimeInterpolator value)
/**
* 设置Evaluator
*/
public
void
setEvaluator(TypeEvaluator value)
|