简介
动画是在开发中比不缺少的展示形式,可以为整个APP增加很多逼格。android动画中分为属性动画和补间动画。补间动画比较简单但是也有不足的地方就是,动画的移动只是表面,真实的坐标还是原来的位置,如果处理一些事件就比较尴尬了。所以就一起来了解了解属性动画。
相关API
Property Animation故名思议就是通过动画的方式改变对象的属性了,我们首先需要了解几个属性:
- Duration动画的持续时间,默认300ms。
- Time interpolation:时间差值,乍一看不知道是什么,但是我说LinearInterpolator、AccelerateDecelerateInterpolator,大家一定知道是干嘛的了,定义动画的变化率。
- Repeat count and behavior:重复次数、以及重复模式;可以定义重复多少次;重复时从头开始,还是反向。
- Animator sets: 动画集合,你可以定义一组动画,一起执行或者顺序执行。
- Frame refresh delay:帧刷新延迟,对于你的动画,多久刷新一次帧;默认为10ms,但最终依赖系统的当前状态;基本不用管。
相关的类 - ObjectAnimator 动画的执行类。
- ValueAnimator 动画的执行类。
- AnimatorSet 用于控制一组动画的执行:线性,一起,每个动画的先后执行等。
- AnimatorInflater 用户加载属性动画的xml文件。
- TypeEvaluator 类型估值,主要用于设置动画操作属性的值。
- TimeInterpolator 时间插值,上面已经介绍。
总的来说,属性动画就是,动画的执行类来设置动画操作的对象的属性、持续时间,开始和结束的属性值,时间差值等,然后系统会根据设置的参数动态的变化对象的属性。
效果图
我们先看下要实现的效果图如下:
实现
通过效果图我们可以看到,是一个圆形从左上角移动到右下角,并且颜色是从蓝色渐变到红色。那么我们可以分为三步走:
- 绘制出一个圆形。
- 实现位移动画。
- 实现渐变动画。
- 效果整合。
一、绘制圆形,此处就直接省略不在介绍了,
二、位移动画,这里我们就要用到刚才介绍到的一个接口TypeEvaluator。通过实现TypeEvaluator接口中的evaluate方法。以下是实现代码:
public class PointEvaluator implements TypeEvaluator{
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
float x = startPoint.getX()+fraction*(endPoint.getX()-startPoint.getX());
float y = startPoint.getY()+fraction*(endPoint.getY()-startPoint.getY());
return new Point(x,y);
}
}
三、 渐变动画,同位移动画一样。
public class ColorEvaluator implements TypeEvaluator {
private int currentRed = -1;
private int currentBlue = -1;
private int currentGreen = -1;
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
//获取开始颜色、结束颜色的值
String startColor = (String) startValue;
String endColor = (String) endValue;
//获取RGB的值
int startRed = Integer.parseInt(startColor.substring(1, 3), 16);
int startGreen = Integer.parseInt(startColor.substring(3, 5), 16);
int startBlue = Integer.parseInt(startColor.substring(5, 7), 16);
int endRed = Integer.parseInt(endColor.substring(1, 3), 16);
int endGreen = Integer.parseInt(endColor.substring(3, 5), 16);
int endBlue = Integer.parseInt(endColor.substring(5, 7), 16);
//初始化各个颜色的值
if (currentRed == -1) {
currentRed = startRed;
}
if (currentGreen == -1) {
currentGreen = startGreen;
}
if (currentBlue == -1) {
currentBlue = startBlue;
}
//计算颜色差
int diffRed = Math.abs(startRed - endRed);
int diffGreen = Math.abs(startGreen - endGreen);
int diffBlue = Math.abs(startBlue - endBlue);
int diffColor = diffRed + diffGreen + diffBlue;
//计算当前颜色值
if (currentRed!=endRed){
currentRed = Math.abs(getCurrentColor(startRed, endRed, diffColor, 0, fraction));
}else if (currentGreen!=endGreen){
currentGreen = Math.abs(getCurrentColor(startGreen,endGreen,diffColor,diffRed,fraction));
}else if (currentBlue!=endBlue){
currentBlue = Math.abs(getCurrentColor(startBlue,endBlue,diffColor,diffRed+diffGreen,fraction));
}
//将当前的值合并成string颜色
String currentColor = "#"+getHexString(currentRed)+getHexString(currentGreen)+getHexString(currentBlue);
return currentColor;
}
private int getCurrentColor(int startColor, int endColor, int diffColor, int i, float fraction) {
int currentColor;
if (startColor > endColor) {
currentColor = (int) (startColor - (fraction * endColor - i));
if (currentColor < endColor) {
currentColor = endColor;
}
} else {
currentColor = (int) (startColor - (fraction * endColor - i));
if (currentColor > endColor) {
currentColor = endColor;
}
}
return currentColor;
}
private String getHexString(int color){
String toHexString = Integer.toHexString(color);
if (toHexString.length()==1){
toHexString = "0"+toHexString;
}
return toHexString;
}
}
四、最后放上整个view的代码,如下:
public class RoundView extends View {
private float radius = 100f;
private Paint paint;
private Point currentPoint;
private String color;
public RoundView(Context context) {
super(context);
init();
}
public RoundView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (currentPoint ==null){
currentPoint = new Point(radius,radius);
startAnimation();
}
canvas.drawCircle(currentPoint.getX(), currentPoint.getY(),radius,paint);
}
private void startAnimation() {
Point startPoint = new Point(radius,radius);
Point endPoint = new Point(getWidth()-radius,getHeight()-radius);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
currentPoint = (Point) valueAnimator.getAnimatedValue();
invalidate();
}
});
ObjectAnimator objectAnimator = ObjectAnimator.ofObject(this,"color",new ColorEvaluator(),"#0000FF","#FF0000");
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
String currentColor = (String) valueAnimator.getAnimatedValue();
Logger.e(RoundView.class.getSimpleName(),currentColor);
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(valueAnimator).with(objectAnimator);
animatorSet.setDuration(5000);
animatorSet.start();
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
paint.setColor(Color.parseColor(color));
invalidate();
}}