前面的文章提到过一个圆环交替效果的自定义View:http://my.oschina.net/august1996/blog/655682
前面的文章中我们通过使用线程去控制mProgress的值然后去从新绘制View来达到动态的效果.其实我们可以通过属性动画去设置我们自定义的动画属性,例如mProgress就是了.下面我们来说一下ObjectAnimator的原理吧.
我们通过ofXXX的方法去设置动画数字区间,然后ObjectAnimator会找到用户所设置的加速器计算得出步进值,然后是计算当前值,最后调用对应属性的set函数.回想一下我们在http://my.oschina.net/august1996/blog/658240,这篇文章说过,怎么知道哪些属性可以改变,就是找那个view的setXXX方法,去掉set就要XXX就是属性了.那下面就直接拿上次的那个代码来修改,原来是这样的
package com.example.customview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
/**
* Created by August on 16/4/9.
*/
public class CircleProgressView extends View {
private int mCircleWidth;
private int mCircleFirstColor;
private int mCircleSecondColor;
private int mSpeed;
/**
* 接收前面设置的属性
*/
private Paint mPaint;
private boolean isSecond = false;
/**
* 当前是否为第二圈
*/
private int mProgress = 0;
/**
* 进度
*/
public CircleProgressView(Context context) {
this(context, null);
}
public CircleProgressView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CircleProgressView, defStyleAttr,
0);
int n = ta.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = ta.getIndex(i);
switch (attr) {
case R.styleable.CircleProgressView_mCircleWidth:
mCircleWidth = ta.getDimensionPixelSize(attr, (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
break;
case R.styleable.CircleProgressView_mCircleFirstColor:
mCircleFirstColor = ta.getColor(attr, 0);
break;
case R.styleable.CircleProgressView_mCircleSecondColor:
mCircleSecondColor = ta.getColor(attr, 0);
break;
case R.styleable.CircleProgressView_mCircleSpeed:
mSpeed = ta.getInteger(attr, 20);
break;
}
}
ta.recycle();
mPaint = new Paint();
new Thread() {
@Override
public void run() {
while (true) {
mProgress++;
if (mProgress == 360) {
mProgress = 0;
isSecond = !isSecond;
/**
* 控制颜色的切换
*/
}
try {
Thread.sleep(mSpeed); // 速度的设置
} catch (InterruptedException e) {
e.printStackTrace();
}
postInvalidate(); // 通过postInvalidate来调用onDraw方法重新绘画
}
}
}.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int center = getWidth() / 2; // 圆心位置,因为圆的半径一致,所以圆心只需确定一次
int radius = center - mCircleWidth; // 确定圆的半径
mPaint.setStrokeWidth(mCircleWidth); // 设置画笔粗细
mPaint.setStyle(Paint.Style.STROKE); // 设置空心画笔,不使用填充
RectF oval = new RectF(center - radius, center - radius, center + radius, center + radius);
/**
* 设置圆的边界
*/
if (isSecond) {
mPaint.setColor(mCircleSecondColor);
canvas.drawCircle(center, center, radius, mPaint); // 画圆
mPaint.setColor(mCircleFirstColor);
canvas.drawArc(oval, 0, mProgress, false, mPaint);
/**
* 0是开始画的度数,参考直角坐标系 0是x的正半轴 90是y的负半轴 180是x的负半轴 270是y的正半轴 可用负数表示
*/
} else {
mPaint.setColor(mCircleFirstColor);
canvas.drawCircle(center, center, radius, mPaint);
mPaint.setColor(mCircleSecondColor);
canvas.drawArc(oval, 0, mProgress, false, mPaint);
}
}
public int getmProgress() {
return mProgress;
}
public void setmProgress(int mProgress) {
this.mProgress = mProgress;
}
}
我们把那个更新mProgress值得线程去掉并且增加方法
public int getmProgress() {
return mProgress;
}
public void setmProgress(int mProgress) {
this.mProgress = mProgress;
}
public void setProgress(int mProgress) {
setmProgress(mProgress);
invalidate();
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<com.example.customview.CircleProgressView
android:id="@+id/mCircleProgressView"
android:layout_width="200dp"
android:layout_height="200dp"
app:mCircleFirstColor="#FF0000"
app:mCircleSecondColor="#00FF00"
app:mCircleSpeed="1"
app:mCircleWidth="30dp" />
</LinearLayout>
然后我们去调用
mCircleProgressView = (CircleProgressView) findViewById(R.id.mCircleProgressView);
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(mCircleProgressView, "Progress", 0, 360);
objectAnimator.setRepeatCount(ObjectAnimator.INFINITE);
objectAnimator.setDuration(1000);
objectAnimator.start();
看,我们增加了那三个方法,然后我们就可以去使用Progress做属性动画了,其中Progress首字母不区分大小写.
动画虽然是可以动了,但是我们发现第二圈的效果没有了.因为我们压根没有改变isSecond的值,下面我们考虑下应该怎么做...
其实很简单,放置一个lastProgress保存上次的进度,因为同一圈的进度都是递增的,所以如果当lastProgress的值大于mProgress的值,则可认为mProgress已经进入了下一圈,于是我们增加变量lastProgress,修改方法:
public void setProgress(int mProgress) {
if (lastProgress > mProgress) {
isSecond = !isSecond;
}
lastProgress = mProgress;
setmProgress(mProgress);
invalidate();
}
我们想要的效果就已经达到了,整体代码:
package com.example.customview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
/**
* Created by August on 16/4/9.
*/
public class CircleProgressView extends View {
private int mCircleWidth;
private int mCircleFirstColor;
private int mCircleSecondColor;
private int mSpeed;
/**
* 接收前面设置的属性
*/
private Paint mPaint;
private boolean isSecond = false;
/**
* 当前是否为第二圈
*/
private int mProgress = 0;
private int lastProgress;
/**
* 进度
*/
public CircleProgressView(Context context) {
this(context, null);
}
public CircleProgressView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CircleProgressView, defStyleAttr,
0);
int n = ta.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = ta.getIndex(i);
switch (attr) {
case R.styleable.CircleProgressView_mCircleWidth:
mCircleWidth = ta.getDimensionPixelSize(attr, (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
break;
case R.styleable.CircleProgressView_mCircleFirstColor:
mCircleFirstColor = ta.getColor(attr, 0);
break;
case R.styleable.CircleProgressView_mCircleSecondColor:
mCircleSecondColor = ta.getColor(attr, 0);
break;
case R.styleable.CircleProgressView_mCircleSpeed:
mSpeed = ta.getInteger(attr, 20);
break;
}
}
ta.recycle();
mPaint = new Paint();
// new Thread() {
// @Override
// public void run() {
// while (true) {
// mProgress++;
// if (mProgress == 360) {
// mProgress = 0;
// isSecond = !isSecond;
// /**
// * 控制颜色的切换
// */
// }
// try {
// Thread.sleep(mSpeed); //速度的设置
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// postInvalidate(); //通过postInvalidate来调用onDraw方法重新绘画
// }
// }
// }.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int center = getWidth() / 2; // 圆心位置,因为圆的半径一致,所以圆心只需确定一次
int radius = center - mCircleWidth; // 确定圆的半径
mPaint.setStrokeWidth(mCircleWidth); // 设置画笔粗细
mPaint.setStyle(Paint.Style.STROKE); // 设置空心画笔,不使用填充
RectF oval = new RectF(center - radius, center - radius, center + radius, center + radius);
/**
* 设置圆的边界
*/
if (isSecond) {
mPaint.setColor(mCircleSecondColor);
canvas.drawCircle(center, center, radius, mPaint); // 画圆
mPaint.setColor(mCircleFirstColor);
canvas.drawArc(oval, 0, mProgress, false, mPaint);
/**
* 0是开始画的度数,参考直角坐标系 0是x的正半轴 90是y的负半轴 180是x的负半轴 270是y的正半轴 可用负数表示
*/
} else {
mPaint.setColor(mCircleFirstColor);
canvas.drawCircle(center, center, radius, mPaint);
mPaint.setColor(mCircleSecondColor);
canvas.drawArc(oval, 0, mProgress, false, mPaint);
}
}
public int getmProgress() {
return mProgress;
}
public void setmProgress(int mProgress) {
this.mProgress = mProgress;
}
public void setProgress(int mProgress) {
if (lastProgress > mProgress) {
isSecond = !isSecond;
}
lastProgress = mProgress;
setmProgress(mProgress);
invalidate();
}
}