package com.example.admin.customtextview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
/**
* Created by admin on 2017/12/12.
*/
public class CustomArc extends View{
private static final String TAG0 = " yyy ";
private static final String TAG = " CustomArc ";
private int default_width = 600;
private int default_height = 600;
private int mWidth;
private int mHeight;
float radius = default_width/4;//圆圈的半径
private Paint mPaint;
private Paint mArcPaint;
private Paint mTickPaint;//对勾
private RectF oval;
private float sweepAngle ;
private float startAngle = 0;
private float mProgress;//进度 0到100
private float mDegrees;//旋转的角度
float startX,startY,stopX,stopY,middleX,middleY,tickWidth,tickHeight,arrowStartX,arrowStartY,arrowMidX,arrowMidY,arrowEndX,arrowEndY;
private boolean mIsStartLongTick;
private float changeTickDegress;
private String mText;
private Paint mTextPaint;
private Integer changeColor;
public CustomArc(Context context) {
this(context,null);
}
public CustomArc(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public CustomArc(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Log.d(TAG0,TAG+" CustomArc()");
//外圆圈的画笔
mPaint = new Paint();
mPaint.setStrokeWidth(10);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.parseColor("#BFBFC0"));
mPaint.setStyle(Paint.Style.STROKE);
mArcPaint = new Paint();
mArcPaint.setStrokeWidth(10);
mArcPaint.setAntiAlias(true);
mArcPaint.setColor(Color.BLUE);
mArcPaint.setStyle(Paint.Style.STROKE);
//对勾的画笔
mTickPaint = new Paint();
mTickPaint.setStrokeWidth(10);
mTickPaint.setAntiAlias(true);
mTickPaint.setColor(Color.parseColor("#BFBFC0"));
mTickPaint.setStyle(Paint.Style.STROKE);
mTickPaint.setStrokeJoin(Paint.Join.ROUND);
mTickPaint.setDither(true);
oval = new RectF();
mText = "i am text";
mTextPaint = new Paint();
mTextPaint.setColor(Color.BLUE);
mTextPaint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d(TAG0,TAG+" onDraw()");
//画最外层圆圈,空心描边
drawOutSideCircle(canvas);
//画进度圆弧,空心,描边
drawArcProgress(canvas);
//画一个对勾路径
drawTick(canvas);
//画文字
drawText(canvas);
}
private void drawText(Canvas canvas) {
float mMeasureText = mTextPaint.measureText(mText);
mTextPaint.setStrokeWidth(10);
mTextPaint.setTextSize(16);
canvas.drawText(mText,mWidth/2 - mMeasureText/2,mHeight/2+radius+mMeasureText,mTextPaint);
}
private void drawTick(Canvas canvas) {
tickWidth = radius/2;
tickHeight = radius/2;
startX = mWidth/2 - tickWidth/2;
startY = mWidth/2 + tickHeight/2;
middleX = mWidth/2 ;
middleY = mWidth/2 - tickHeight/2;
stopX = middleX + tickWidth/2;
stopY = middleY + tickHeight;
arrowStartX = mWidth/2+radius*3/4;
arrowStartY = mWidth/2-radius*1/4;
arrowMidX = mWidth/2+radius;
arrowMidY = mHeight/2;
arrowEndX = arrowMidX+radius*1/4;
arrowEndY = arrowMidY-radius*1/4;
if(mIsStartLongTick) {
startX-=mProgress/5;
startY+=mProgress/5;
mTickPaint.setColor(Color.BLUE);
}
mDegrees = mProgress*3.6f;
canvas.save();
canvas.rotate(mDegrees,mWidth/2,mWidth/2);//180度旋转
canvas.rotate(changeTickDegress,mWidth/2,mWidth/2);//一定要先于目的view的绘制调用,才能让目的view跟着一起动;360度
Path path = new Path();
path.moveTo(startX,startY);
path.lineTo(middleX,middleY);
path.lineTo(stopX,stopY);
canvas.drawPath(path,mTickPaint);
/*
一个绕着圆圈转的箭头
Path arrowPath = new Path();
arrowPath.moveTo(arrowStartX,arrowStartY);
arrowPath.lineTo(arrowMidX,arrowMidY);
arrowPath.lineTo(arrowEndX,arrowEndY);
canvas.drawPath(arrowPath,mTickPaint);*/
canvas.restore();//一定记得还原画布,否则在它之后的view也会跟着转动
}
private void drawOutSideCircle(Canvas canvas) {
canvas.drawCircle(mWidth/2,mHeight/2,radius,mPaint);
}
private void drawArcProgress(Canvas canvas) {
if(changeColor != null) {
mArcPaint.setColor((int) changeColor);
}
sweepAngle = mProgress * 3.6f;
oval.set(mWidth/2-radius,mWidth/2-radius,mWidth/2+radius,mWidth/2+radius);
canvas.drawArc(oval,startAngle, sweepAngle,false,mArcPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG0,TAG+" onMeasure()");
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
int width,height;
if(widthMode == MeasureSpec.EXACTLY) {
width = measureWidth;
}else {
width = default_width;
}
if(heightMode == MeasureSpec.EXACTLY) {
height = measureHeight;
}else {
height = default_height;
}
setMeasuredDimension(width,height);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.d(TAG0,TAG+" onLayout() mWidth = "+mWidth+" mHeight ="+mHeight +" changed = "+changed+" left = "+left+" top = "+top+" right = "+right+" bottom = "+bottom);
mWidth = getWidth();
mHeight = getHeight();
radius = mWidth/4;
}
public void startAnim() {
/* 1.ValueAnimator va = ValueAnimator.ofFloat(0,100,0);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mProgress = (float) animation.getAnimatedValue();
Log.d(TAG0, TAG + " mProgress = " + mProgress);
postInvalidate();
}});
va.setRepeatCount(0);
va.setRepeatMode(ValueAnimator.RESTART);
va.setDuration(5000);
va.start();*/
//2.和1可以起到同样的作用
ValueAnimator va = ValueAnimator.ofObject(new MyObjTypeEva(),0.0f,100f);
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
Log.d(TAG0,TAG+"ValueAnimator.ofObject(): onAnimationEnd() :mProgress = "+mProgress);
start180Anim();
}
});
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mProgress = (float) animation.getAnimatedValue();
mText = mProgress+"%";
Log.d(TAG0,TAG+" onAnimationUpdate() :mProgress = "+mProgress);
postInvalidate();
}
});
va.setDuration(5000);
va.setRepeatCount(0);
va.start();
startColorAnim();//颜色渐变的属性动画
}
private void start180Anim() {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,180f);
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
Log.d(TAG0,TAG+" start180Anim():onAnimationUpdate() :mProgress = "+mProgress);
mIsStartLongTick = true;
mText = "完成";
postInvalidate();
}
});
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
changeTickDegress = (float) animation.getAnimatedValue();
postInvalidate();
}
});
valueAnimator.setDuration(2000);
valueAnimator.start();
valueAnimator.setRepeatCount(0);
}
class MyObjTypeEva implements TypeEvaluator {
/**
*
* @param fraction 0到1之间,表示当前动画的速率
* @param startValue 动画起始值
* @param endValue 动画结束值
* @return
*/
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
float fEndValue = (float) endValue;
float fStartValue = (float) startValue;
Log.d(TAG0,TAG+" evaluate() :fraction = "+fraction+" fStartValue = "+fStartValue+" fEndValue = "+fEndValue);
return fraction*(fEndValue - fStartValue);
}
}
public void startColorAnim() {
ValueAnimator va = ValueAnimator.ofArgb(0xffffffff,0xffff0000,0xff0000ff);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
changeColor = (Integer) animation.getAnimatedValue();
Log.d(TAG0,TAG+" onAnimationUpdate():changeColor = "+changeColor);
postInvalidate();
}
});
va.setDuration(5000);
va.setRepeatCount(0);
va.start();
}
}
此view实现了一个带进度的圆弧,max是360,中间伴随着颜色的变化,以及画路径方法的使用,知识点比较多,详情,看代码。