最近做项目要求做一个类似腾讯WiFi网络检测的动画,最近正好项目开发完成,手头也没什么事,就给大家分享一下。当时项目也非常紧为了赶周期就没考虑代码优化的问题,希望大拿们不喜勿喷。
话不多说先来看看效果(转成GIF后比较卡顿)
第一步:在没有旋转动画之前呢是一个图片,把图片和自定义的旋转动画放在一个Layout当中,当开始检测的时候就打开自定义试图的动画。
布局文件
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<com.zhizun.zhizunwifi.widget.CircleViewPhy
android:id="@+id/circle_safe"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
app:circleWidth="2dp"
app:firstColor="@color/white"
app:speed="2"
android:visibility="gone"
/>
<ImageView
android:id="@+id/speed_rotating"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:src="@drawable/img_scanning"
android:layout_gravity="center_vertical"
android:visibility="gone"
/>
<ImageView
android:id="@+id/speed_icon_safe"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_centerInParent="true"
android:src="@drawable/icon_safe"
android:layout_gravity="center_vertical"
/>
</RelativeLayout>
speed_icon_safe这个就是一张图片,speed_rotating中间旋转渐变的扇形图片,circle_safe从开始画圆点然后圆弧旋转一直到检测完毕画实心圆弧都有这个自定义试图完成。
第二步:关键的自定义试图代码
public class CircleViewPhy extends View {
/**
* 第一种颜色
*/
private int mFirstColor;
/**
* 第二种颜色
*/
private int mSecondColor;
/**
* 圆弧的宽度
*/
private int mCircleWidth;
/**
* 画笔
*/
private Paint mPaint;
private Paint wPaint;
private Paint TPaint;
/**
* 圆弧的度数
*/
private int mProgress;
/**
* 圆弧的度数
*/
private int TProgress;
/**
* 圆弧绘制的速度
*/
private int mSpeed;
/**
* 是不是开始绘制下一个圆弧
*/
private boolean isNext = false;
private int phase;
private Rect mSrcRect, mDestRect;
private float mStartAngle;
private float mSweepAngle = 0;
private static final int MIN_ANGLE_SWEEP = 3;
private static final int MAX_ANGLE_SWEEP = 155;
private int mAngleIncrement = 3;
Bitmap bmp;
private ImageView imageCircle;
private Context mContext;
private boolean isFinsh = false;
private boolean autoRun = false;
public CircleViewPhy(Context context) {
this(context, null);
}
public CircleViewPhy(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public void setImageCircle(ImageView imageCircle) {
this.imageCircle = imageCircle;
}
public void setfinsh(boolean finsh){
this.isFinsh = finsh;
}
public void setautoRun(boolean run){
this.autoRun = run;
}
/**
* 获取自定义控件的一些值
*
* @param context
* @param attrs
* @param defStyleAttr
*/
public CircleViewPhy(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CircleViewPhy, defStyleAttr, 0);
mContext = context;
for (int i = 0; i < a.getIndexCount(); i++) {
switch (a.getIndex(i)) {
case R.styleable.CircleViewPhy_firstColor:
mFirstColor = a.getColor(a.getIndex(i), Color.WHITE);
break;
case R.styleable.CircleViewPhy_secondColor:
mSecondColor = a.getColor(a.getIndex(i), Color.RED);
break;
case R.styleable.CircleViewPhy_speed:
mSpeed = a.getInt(a.getIndex(i), 20);
break;
case R.styleable.CircleViewPhy_circleWidth:
mCircleWidth = a.getDimensionPixelOffset(a.getIndex(i), (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, 20, getResources().getDisplayMetrics()));
break;
}
}
a.recycle();
mPaint = new Paint();
wPaint = new Paint();
TPaint = new Paint();
//绘图线程
new Thread() {
@Override
public void run() {
while (true) {
if (autoRun){
if (isFinsh){
TProgress ++;
if (TProgress == 360){
TProgress = 360;
}
}
if (mProgress != 360) {
mProgress++;
}else {
final float angle = 5;
mStartAngle += angle;
if (mStartAngle > 360) {
mStartAngle -= 360;
}
if (mSweepAngle > MAX_ANGLE_SWEEP) {
mAngleIncrement = -mAngleIncrement;
} else if (mSweepAngle < MIN_ANGLE_SWEEP) {
mSweepAngle = MIN_ANGLE_SWEEP;
} else if (mSweepAngle == MIN_ANGLE_SWEEP) {
mAngleIncrement = -mAngleIncrement;
}
mSweepAngle += mAngleIncrement;
}
}
postInvalidate();
try {
if (mProgress == 360 && !isFinsh){
Thread.sleep(mSpeed + 5); //通过传递过来的速度参数来决定线程休眠的时间从而达到绘制速度的快慢
}else {
Thread.sleep(mSpeed); //通过传递过来的速度参数来决定线程休眠的时间从而达到绘制速度的快慢
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
@Override
protected void onDraw(Canvas canvas) {
int center = getWidth() / 2;
int radius = center - mCircleWidth / 2;
mPaint.setStrokeWidth(mCircleWidth); // 设置圆环的宽度
wPaint.setStrokeWidth(mCircleWidth);
TPaint.setStrokeWidth(mCircleWidth + 8);
mPaint.setAntiAlias(true); // 消除锯齿
wPaint.setAntiAlias(true); // 消除锯齿
TPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE); // 设置空心
wPaint.setStyle(Paint.Style.STROKE);
TPaint.setStyle(Paint.Style.STROKE);
RectF oval = new RectF(center - radius + 5, center - radius + 5, center + radius - 5, center + radius - 5); // 用于定义的圆弧的形状和大小的界限
RectF oval0 = new RectF(center - radius + 50, center - radius + 50, center + radius - 50, center + radius - 50); // 用于定义的圆弧的形状和大小的界限
if (!isFinsh){
Path path = new Path();
path.addCircle(0, 0, 5, Path.Direction.CCW);
PathEffect pathEffect = new PathDashPathEffect(path,30, phase, PathDashPathEffect.Style.ROTATE);
mPaint.setPathEffect(pathEffect);
mPaint.setColor(mFirstColor); // 设置圆环的颜色
canvas.drawArc(oval, -90, mProgress, false, mPaint); // 根据进度画圆弧
if (mProgress == 360){
wPaint.setColor(getResources().getColor(R.color.white_alpha_144)); // 设置圆环的颜色
canvas.drawArc(oval0, -90, 360, false, wPaint);
TPaint.setColor(Color.WHITE);
canvas.drawArc(oval, mStartAngle, mSweepAngle, false, TPaint);
}
}else {
wPaint.setColor(getResources().getColor(R.color.white)); // 设置圆环的颜色
canvas.drawArc(oval0, -90, TProgress, false, wPaint);
}
}
}
当时本来说是圆环要颜色变化的,但是后来统一改成白色了,所以代码中颜色的片段就不用管了。我先来说说思路,首先动画开始是一个圆点的画圆弧动画。
把笔触设置为圆点
Path path = new Path();
path.addCircle(0, 0, 5, Path.Direction.CCW);
PathEffect pathEffect = new PathDashPathEffect(path,30, phase, PathDashPathEffect.Style.ROTATE);
mPaint.setPathEffect(pathEffect);
所有的动画效果都是通过画笔在画图的过程中设置一个线程休眠来体现的。
postInvalidate();
try {
if (mProgress == 360 && !isFinsh){
Thread.sleep(mSpeed + 5); //通过传递过来的速度参数来决定线程休眠的时间从而达到绘制速度的快慢
}else {
Thread.sleep(mSpeed); //通过传递过来的速度参数来决定线程休眠的时间从而达到绘制速度的快慢
}
} catch (InterruptedException e) {
e.printStackTrace();
}
当圆点的圆弧画到360度之后就开始画第二层的实心圆
if (mProgress == 360){
wPaint.setColor(getResources().getColor(R.color.white_alpha_144)); // 设置圆环的颜色
canvas.drawArc(oval0, -90, 360, false, wPaint);
TPaint.setColor(Color.WHITE);
canvas.drawArc(oval, mStartAngle, mSweepAngle, false, TPaint);
}
<declare-styleable name="CircleViewPhy">
<attr name="firstColor" format="color"/>
<attr name="secondColor" format="color"/>
<attr name="circleWidth" format="dimension"/>
<attr name="speed" format="integer"/>
</declare-styleable>
当检测过程完毕之后又Activity传入isFinsh为True标识完毕,停止绘制动画,画最后一层高亮的圆弧。