自定义View的步骤:
2、在View的构造方法中获得我们自定义的属性
3、重写onMesure (有时非必须)
4、重写onDraw
找到res/values/attrs.xml(没有则需创建)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--自定义属性集-->
<declare-styleable name="LoadCircleView">
<!--圆的半径-->
<attr name="circle_radius" format="float" />
<!--持续时间-->
<attr name="duration" format="integer" />
</declare-styleable>
</resources>
编写我们的View
public class LoadCircleView extends View {
/**
* 第一个动画的索引
*/
private int changeIndex = 0;
/**
* 圆的颜色值
*/
private int[] colors = new int[]{
getResources().getColor(R.color.color_red),
getResources().getColor(R.color.color_blue),
getResources().getColor(R.color.color_black)};
/**
* 偏移量
*/
private Float maxWidth = 50f;
/**
* 圆的半径 默认10f
*/
private Float circleRadius = 10f;
/**
* 当前偏移的X坐标
*/
private Float currentX = 0f;
/**
* 画笔
*/
private Paint paint;
/**
* 属性动画
*/
private ValueAnimator valueAnimator;
/**
* 持续时间
*/
private int duration = 800;
/**
* 默认的布局文件调用的是两个参数的构造方法
* 让所有的构造调用我们的三个参数的构造
* 在三个参数的构造中获得自定义属性
*/
public LoadCircleView(Context context) {
this(context,null);
}
public LoadCircleView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public LoadCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
if (null != attrs) {
//获得对控件自定义属性集的引用
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.LoadCircleView);
circleRadius = typedArray.getFloat(R.styleable.LoadCircleView_circle_radius,circleRadius);
duration = typedArray.getInt(R.styleable.LoadCircleView_duration,duration);
typedArray.recycle();//记得回收
}
startAnimator();
}
/**
* 位移动画
*/
private void startAnimator(){
valueAnimator = ValueAnimator.ofFloat(0f,maxWidth,0);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentX = (Float)animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
changePoint(changeIndex);
}
});
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setRepeatCount(-1);
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
valueAnimator.setDuration(duration);
valueAnimator.start();
}
/**
* 先执行动画的目标和中间停止的动画目标交换
*
* @param index 最先执行的动画的索引
*/
private void changePoint(int index) {
int temp = colors[2];
colors[2] = colors[index];
colors[index] = temp;
changeIndex = (index == 0) ? 1 : 0;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
/**左边圆**/
paint.setColor(colors[0]);
canvas.drawCircle(centerX - currentX, centerY, circleRadius, paint);
/**右边圆**/
paint.setColor(colors[1]);
canvas.drawCircle(centerX + currentX, centerY, circleRadius, paint);
/**中间圆**/
paint.setColor(colors[2]);
canvas.drawCircle(centerX, centerY, circleRadius, paint);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
valueAnimator.cancel();
}
}
View的构造方法中,获取我们的属性,并开始动画
使用ValueAnimator实现动画的步骤:
1. 调用ValueAnimation类中的ofInt(int...values)、ofFloat(String propertyName,float...values)等静态方法实例化ValueAnimator对象,并设置目标属性的属性名、初始值或结束值等值;
2.调用addUpdateListener(AnimatorUpdateListener mListener)方法为ValueAnimator对象设置属性变化的监听器;
3.创建自定义的Interpolator,调用setInterpolator(TimeInterpolator value)为ValueAniamtor设置自定义的Interpolator;(可选,不设置默认为缺省值)
4.创建自定义的TypeEvaluator,调用setEvaluator(TypeEvaluator value)为ValueAnimator设置自定义的TypeEvaluator;(可选,不设置默认为缺省值)
5.在AnimatorUpdateListener 中的实现方法为目标对象的属性设置计算好的属性值。
6.设置动画的持续时间、是否重复及重复次数等属性;
7.为ValueAnimator设置目标对象并开始执行动画。