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,中间伴随着颜色的变化,以及画路径方法的使用,知识点比较多,详情,看代码。
自定义view和属性动画的结合使用
最新推荐文章于 2021-05-25 14:36:31 发布