用Canvas画带动画的渐变数字圆环

xiaoxiao2021-02-27  297

项目在github上的地址:

https://github.com/Hebin320/ArcChart


上的下载地址

http://download.csdn.net/detail/hebin320320/9498435


先放效果图

这是一个自定义view,布局就是一个简单的线性布局而已,通过addview的方式,将自定义view显示出来;  渐变圆以及外圈圆、外圈小圆是自定义view,其他三个文字是Textview;

布局代码:

<LinearLayout android:id="@+id/doughnutView_passenger" android:layout_width="@dimen/margin_180" android:layout_height="@dimen/margin_180" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/margin_20" android:orientation="vertical" /> <com.zerom.fitting.custom.textview.RiseNumberTextView android:id="@+id/tv_passenger_num" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/margin_50" android:textColor="@color/white" android:textSize="@dimen/margin_55" /> <TextView android:id="@+id/tv_passenger_num_01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tv_passenger_num" android:layout_centerHorizontal="true" android:textColor="@color/home_passenger" android:textSize="@dimen/text_size_16" /> <TextView android:id="@+id/tv_passenger_num_02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tv_passenger_num_01" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/margin_2" android:textColor="@color/home_passenger" android:textSize="@dimen/text_size_14" /> 1234567891011121314151617181920212223242526272829303132333435 1234567891011121314151617181920212223242526272829303132333435

自定义view代码:

public class HomeArcView extends View { //圆环颜色 private int[] doughnutColors = {Color.parseColor("#42e7e0"), Color.parseColor("#91ffa1"), Color.parseColor("#5ef0c9")}; private int roundColor=ContextCompat.getColor(getContext(),R.color.home_passenger); private Paint paint_white; private static float currentValue = 0f; private Paint paint = new Paint(); private float arc_y = 0f; private float arc_y_1 = 0f; private int score, mPage; private int pointCount = 2; private float tb; private float doughnutWidth; private RectF rectf; public HomeArcView(Context context, int score) { super(context); setValue(score); } public HomeArcView(Context context, AttributeSet attrs) { super(context, attrs); } public HomeArcView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private void initPaint() { paint.reset(); paint.setAntiAlias(true); } public void setValue(int score) { this.score = score; Resources res = getResources(); tb = res.getDimension(R.dimen.margin_10); doughnutWidth = 0.25f * tb; //外圈圆 rectf = new RectF(); rectf.set(doughnutWidth * 2, doughnutWidth * 2, 17.5f * tb, 17.5f * tb); ValueAnimator valueAnimator = ValueAnimator.ofFloat(currentValue, 360f); valueAnimator.setInterpolator(new Interpolator() { @Override public float getInterpolation(float v) { return 1 - (1 - v) * (1 - v) * (1 - v); } }); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { currentValue = (float) valueAnimator.getAnimatedValue(); invalidate(); } }); valueAnimator.start(); //圆圈带颜色 paint_white = new Paint(); paint_white.setAntiAlias(true); paint_white.setColor(roundColor); paint_white.setStrokeWidth(tb * 0.2f); paint_white.setTextAlign(Paint.Align.CENTER); paint_white.setStyle(Paint.Style.STROKE); //外圈圆第一部分动画,0 至 score-1 this.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { new thread(); getViewTreeObserver().removeOnPreDrawListener(this); return false; } }); //外圈圆第二部分动画,score+1 至 100 this.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { new threadone(); getViewTreeObserver().removeOnPreDrawListener(this); return false; } }); //外圈小圆动画,0 到 score this.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { new threadtwo(); getViewTreeObserver().removeOnPreDrawListener(this); return false; } }); } @Override protected void onDraw(Canvas canvas) { initPaint(); //渐变色圆 drawSq(canvas); //外圈小圆 drawPoint(canvas); //外圈圆第一部分 drawOneSq(canvas); //外圈圆第二部分 drawTwoSq(canvas); } /** * 画内圈渐变圆 */ private void drawSq(Canvas canvas) { RectF rectF = new RectF(doughnutWidth * 6, doughnutWidth * 6, 16.5f * tb, 16.5f * tb); paint.setStrokeWidth(doughnutWidth * 2); paint.setStyle(Paint.Style.STROKE); if (doughnutColors.length > 1) { paint.setShader(new SweepGradient(7.5f * tb, 7.5f * tb, doughnutColors, null)); } else { paint.setColor(doughnutColors[0]); } canvas.drawArc(rectF, 0, currentValue, false, paint); } /** * 画外圆第一部分 */ private void drawOneSq(Canvas canvas) { canvas.rotate(0, getWidth() / 2, getHeight() / 2); canvas.drawArc(rectf, -90, arc_y, false, paint_white); } class thread implements Runnable { private Thread thread; private int statek; int count; public thread() { thread = new Thread(this); thread.start(); } public void run() { while (true) { switch (statek) { case 0: try { Thread.sleep(400); statek = 1; } catch (InterruptedException e) { } break; case 1: try { Thread.sleep(15); arc_y += 3.6f; count++; postInvalidate(); } catch (InterruptedException e) { e.printStackTrace(); } break; } if (count >= score - 2) break; } } } /** * 画外圆第二部分 */ private void drawTwoSq(Canvas canvas) { canvas.rotate((float) ((score + 2) * 3.6), getWidth() / 2, getHeight() / 2); canvas.drawArc(rectf, -90, arc_y_1, false, paint_white); } class threadone implements Runnable { private Thread thread; private int statek = 1; int count = score + 2; public threadone() { thread = new Thread(this); thread.start(); } public void run() { while (true) { switch (statek) { case 1: try { Thread.sleep(5); arc_y_1 += 3.6f; count++; postInvalidate(); } catch (InterruptedException e) { e.printStackTrace(); } break; } if (count >= 100) break; } } } /** * 画外圆圆点 */ private void drawPoint(Canvas canvas) { Paint paint_big_text = new Paint(); paint_big_text.setAntiAlias(true); paint_big_text.setColor(Color.WHITE); paint_big_text.setTextAlign(Paint.Align.CENTER); paint_big_text.setStyle(Paint.Style.FILL); initPaint(); canvas.drawCircle((float) (9.0f * tb + 8.5f * tb * Math.sin(3.6 * pointCount * Math.PI / 180)), (float) (9.0f * tb - 8.5f * tb * Math.cos(3.6 * pointCount * Math.PI / 180)), 10, paint_big_text); } class threadtwo implements Runnable { private Thread thread; private int statek = 0; public threadtwo() { thread = new Thread(this); thread.start(); } public void run() { while (true) { switch (statek) { case 0: try { Thread.sleep(400); statek = 1; } catch (InterruptedException e) { } break; case 1: try { Thread.sleep(15); pointCount++; postInvalidate(); } catch (InterruptedException e) { e.printStackTrace(); } break; } if (pointCount >= score) break; } } } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264

在Activity中应用:

doughnutViewPassenger.removeAllViews(); doughnutViewPassenger.addView(new HomeArcView(this, 90)); BaseMethod.AnimaText(tvPassengerNum, 90); tvPassengerNum01.setText(""); tvPassengerNum02.setText(""); 12345 12345

AnimaText方法:

/** * 给一个TextView设置一个数字增长动画 * */ public static void AnimaText(RiseNumberTextView tv , int number){ // 设置数据 tv.withNumber(number); // 设置动画播放时间 tv.setDuration(1500); tv.start(); } 12345678910 12345678910

数字增长动画,重写Textview:

/** * 增长的数字接口 * */ public interface IRiseNumber { /** * 开始播放动画的方法 */ public void start(); /** * 设置小数 * * @param number * @return */ public void withNumber(float number); /** * 设置整数 * * @param number * @return */ public void withNumber(int number); /** * 设置动画播放时长 * * @param duration * @return */ public void setDuration(long duration); /** * 设置动画结束监听器 * * @param callback */ public void setOnEndListener(RiseNumberTextView.EndListener callback); } 1234567891011121314151617181920212223242526272829303132333435363738394041 1234567891011121314151617181920212223242526272829303132333435363738394041 /** * 自定义RiseNumberTextView继承TextView,并实现接口RiseNumberBase * */ public class RiseNumberTextView extends TextView implements IRiseNumber { private static final int STOPPED = 0; private static final int RUNNING = 1; private int mPlayingState = STOPPED; private float number; private float fromNumber; /** * 动画播放时长 */ private long duration = 1500; /** * 1.int 2.float */ private int numberType = 2; private DecimalFormat fnum; private EndListener mEndListener = null; final static int[] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE }; /** * 构造方法 * * @param context */ public RiseNumberTextView(Context context) { super(context); } /** * 使用xml布局文件默认的被调用的构造方法 * * @param context * @param attr */ public RiseNumberTextView(Context context, AttributeSet attr) { super(context, attr); // setTextColor(context.getResources().getColor(R.color.red)); // setTextSize(30); } public RiseNumberTextView(Context context, AttributeSet attr, int defStyle) { super(context, attr, defStyle); } /** * 判断动画是否正在播放 * * @return */ public boolean isRunning() { return (mPlayingState == RUNNING); } /** * 跑小数动画 */ private void runFloat() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(fromNumber, number); valueAnimator.setDuration(duration); valueAnimator .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { setText(fnum.format(Float.parseFloat(valueAnimator .getAnimatedValue().toString()))); if (valueAnimator.getAnimatedFraction() >= 1) { mPlayingState = STOPPED; if (mEndListener != null) mEndListener.onEndFinish(); } } }); valueAnimator.start(); } /** * 跑整数动画 */ private void runInt() { ValueAnimator valueAnimator = ValueAnimator.ofInt((int) fromNumber, (int) number); valueAnimator.setDuration(duration); valueAnimator .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { //设置瞬时的数据值到界面上 setText(valueAnimator.getAnimatedValue().toString()); if (valueAnimator.getAnimatedFraction() >= 1) { //设置状态为停止 mPlayingState = STOPPED; if (mEndListener != null) //通知监听器,动画结束事件 mEndListener.onEndFinish(); } } }); valueAnimator.start(); } static int sizeOfInt(int x) { for (int i = 0;; i++){ if (x <= sizeTable[i]) return i + 1; } } @Override protected void onFinishInflate() { super.onFinishInflate(); fnum = new DecimalFormat("##0.00"); } /** * 开始播放动画 */ @Override public void start() { if (!isRunning()) { mPlayingState = RUNNING; if (numberType == 1) runInt(); else runFloat(); } } /** * 设置一个小数进来 */ @Override public void withNumber(float number) { this.number = number; numberType = 2; if (number > 1000) { fromNumber = number - (float) Math.pow(10, sizeOfInt((int) number) - 1); } else { fromNumber = number / 2; } } /** * 设置一个整数进来 */ @Override public void withNumber(int number) { this.number = number; numberType = 1; if (number > 1000) { fromNumber = number - (float) Math.pow(10, sizeOfInt((int) number) - 2); } else { fromNumber = number / 2; } } /** * 设置动画播放时间 */ @Override public void setDuration(long duration) { this.duration = duration; } /** * 设置动画结束监听器 */ @Override public void setOnEndListener(EndListener callback) { mEndListener = callback; } /** * 定义动画结束接口 * * */ public interface EndListener { /** * 当动画播放结束时的回调方法 */ public void onEndFinish(); } }
转载请注明原文地址: https://www.6miu.com/read-2245.html

最新回复(0)