属性(Property)动画:安卓提供的众多动画中的一种,从某种角度来看,属性动画实际上是增强版的补间(Tween)动画。
属性动画主要由两方面组成:
1.计算各帧的相关属性值。
2.给指定的对象设置相关的属性值。
区别:
1.补间(Tween)动画只能够操控各种组件的透明度(alpha),位置(translate),
旋转(rotate)和放缩(scale)四种属性进行相应的变换,但是属性(Property)动画可以对任何的属性值做出改变。
2.补间(Tween)动画只能对UI组件作用,但是属性(Property)动画没有限制,可以对任何对象进行操作。
属性动画API:
1.ValueAnimator:属性动画主要的时间引擎,它负责计算各个帧的属性值,也就是属性动画第一组成部分。由于ValueAnimator只会负责第一部分,第二部分给组件赋属性值就需要手动完成。
2.ObjectAnimator:ValueAnimator的子类,在使用的时候可以直接指定组件对象,使用起来更加的方便了。但是在某些场景下,ObjectAnimator存在一些限制,可能需要考虑使用ValueAnimator。
3.AnimatorSet:Animator的子类,可以用于组合多个Animator对象,还可以指定是按次序播放还是同时播放。
在ValueAnimator中还用到了一个计算工具类Evaluator(计算器),控制者属性动画如何计算属性值。Android提供了集中Evaluator:
1.IntEvaluator:用于计算int类型的属性值计算器。
2.FloatEvaluator:用于计算float类型的属性值计算器。
3.ArgbEvaluator:用于计算十六进制的rgb颜色值。
4.TypeEvaluator:计算器的接口,供自定义计算器实现。
使用ValueAnimator创建动画大致如下四个步骤:
1.调用ValueAnimator的ofInt(), ofFloat(), ofObject()静态方法创建ValueAnimator实例,很明显这几个不同的方法创建的不同实例中,所用到的计算器也是不同的。
2.调用ValueAnimator的setDuration()等方法给属性动画设置相应的参数,如动画的持续时间,重复次数等。
3.调用start()方法启动相应的动画。
4.为ValueAnimator注册AnimatorUpdateListener监听器,在监听器中可以实时获取到ValueAnimator计算出来的属性值,只需要在监听器中赋值给对应对象就行了。
例如:
ValueAnimator animation = ValueAnimator.ofFloat(1f, 0f);
animation.setDuration(3000);
animation.setRepeatCount(1);
animation.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
/**
* 使用的时候可以通过getAnimatedValue()来获取当前计算出来的帧的属性值,并赋值给制定对象。
*/
}
});
如果是希望使用自己利用TypeEvaluator定义出来的属性值计算器,则将第一步改为:
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(),1f, 0f);
2.使用ObjectAnimator创建动画和ValueAnimator差不多,只不过ObjectAnimator已经实现了将计算结果赋值给对象,我们在使用的时候提供控件对象,
不需要注册AnimatorUpdateListener监听器(没有上述的第四个步骤)。
例如:
ObjectAnimator animation = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1f);
animation.setDuration(1000);
animation.setRepeatCount(1);
animation.start();
注意:
1.在使用ObjectAnimator的对象上一定要有改变的属性值,例如上述的例子中imageView一定要有alpha这个属性值。
2.如果在第一句话是
ObjectAnimator animation = ObjectAnimator.ofFloat(imageView, "alpha", 1f);
少提供了一个参数,则提供的值会被认为是属性计算的结束值,对alpha这个属性一定要提供getter方法,返回的值将作为属性计算的初始值,也就是从该组件的当前状态开始执行动画。
3.如果动画的对象是View,为了能显示动画的效果,需要不断的通知组件重新绘制,调用View.invalidate()方法,
但是View定义的setter方法,如setAloha()等方法都会自动的调用invalidate()方法,不需要我们再额外的调用了。
/**
* 图形类
* 在实例中是一个圆
*/
public class ShapeHolder {
private float x = 0, y = 0;
private ShapeDrawable shape;
private int color;
private RadialGradient gradient;
private float alpha = 1f;
private Paint paint;
public ShapeHolder(ShapeDrawable s) {
shape = s;
}
public float getWidth() {
return shape.getShape().getWidth();
}
public void setWidth(float width) {
Shape s = shape.getShape();
s.resize(width,s.getWidth());
}
public float getHeight() {
return shape.getShape().getHeight();
}
public void setHeight(float height) {
Shape s = shape.getShape();
s.resize(height,s.getHeight());
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public ShapeDrawable getShape() {
return shape;
}
public void setShape(ShapeDrawable shape) {
this.shape = shape;
}
public RadialGradient getGradient() {
return gradient;
}
public void setGradient(RadialGradient gradient) {
this.gradient = gradient;
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
}
public Paint getPaint() {
return paint;
}
public void setPaint(Paint paint) {
this.paint = paint;
}
}
public class MainActivity extends Activity {
static final float BALL_SIZE = 50F;
/**
* 用来控制动画执行的时间
*/
static final float FULL_TIME = 1000;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout container = (LinearLayout) findViewById(R.id.root);
/**
* 将自定义控件加入到布局中
*/
container.addView(new MyAniamtionView(this));
}
/**
* 自定义View
* 实现了AnimatorUpdateListener监听类
*/
public class MyAniamtionView extends View implements ValueAnimator.AnimatorUpdateListener {
/**
* 存储多个小球的容器
*/
public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();
public MyAniamtionView(Context context) {
super(context);
setBackgroundColor(Color.WHITE);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//在手指触摸的地方添加一个小球
ShapeHolder newBall = addBall(event.getX(), event.getY());
float startY = newBall.getY();
float endY = getHeight() - BALL_SIZE;
float h = (float) getHeight();
float eventY = event.getY();
int duration = (int) (FULL_TIME * ((h - eventY) / h));
//用ValueAnimator定义落下的动画
ValueAnimator fallAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY);
fallAnim.setDuration(duration);
fallAnim.setInterpolator(new AccelerateInterpolator());
//用ObjectAnimator定义落下的动画
ObjectAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY, startY);
bounceBackAnim.setDuration(duration);
bounceBackAnim.setInterpolator(new DecelerateInterpolator());
fallAnim.addUpdateListener(this);
//定义小球透明度的动画
ObjectAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}
});
fadeAnim.addUpdateListener(this);
//定义一个AnimatorSet来将定义的三个动画排序
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(fallAnim).before(bounceBackAnim); animatorSet.play(bounceBackAnim).before(fadeAnim);
animatorSet.start();
return true;
}
/**
* 向小球集合ArrayList中加入小球
* 设置各种属性坐标等
*
* @param x
* @param y
* @return
*/
private ShapeHolder addBall(float x, float y) {
OvalShape circle = new OvalShape();
circle.resize(BALL_SIZE, BALL_SIZE);
ShapeDrawable drawable = new ShapeDrawable(circle);
ShapeHolder shapeHolder = new ShapeHolder(drawable);
shapeHolder.setX(x - BALL_SIZE / 2);
shapeHolder.setY(y - BALL_SIZE / 2);
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
int color = 0xff000000 + red << 16 | green << 8 | blue;
Paint paint = drawable.getPaint();
int drakColor = 0xff000000 | red / 4 << 16 | green / 4 << 8 | blue /4;
RadialGradient gradient = new RadialGradient(37.5f, 12.5f, BALL_SIZE, color, drakColor,
Shader.TileMode.CLAMP);
paint.setShader(gradient);
shapeHolder.setPaint(paint);
balls.add(shapeHolder);
return shapeHolder;
}
/**
* 将集合里的每个小球都绘制在屏幕上面
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
for (ShapeHolder shapeHolder : balls) {
canvas.save();
canvas.translate(shapeHolder.getX(), shapeHolder.getY());
shapeHolder.getShape().draw(canvas);
canvas.restore();
}
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
this.invalidate();
}
}
}
原文地址:http://blog.csdn.net/jing_unique_da/article/details/44025705