自定义View,仿蚂蚁芝麻分仪表盘(早前的一版)

2023-10-17 07:10

本文主要是介绍自定义View,仿蚂蚁芝麻分仪表盘(早前的一版),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

整理代码,发现了这个3年前写的一个view,记得当时也是参考了某大佬的博客写的,记不清了,因为这个view还是有一些知识点的,所以写下来记录一下吧

先看下最后的效果

 

上代码,具体的细节,在代码中参悟吧

样式

    <declare-styleable name="RoundIndicatorView"><!--最大数值--><attr name="maxNum" format="integer"/><!--圆盘起始角度--><attr name="startAngle" format="integer"/><!--圆盘扫过的角度--><attr name="sweepAngle" format="integer"/></declare-styleable>

代码

package com.xinxin.applicationtest.widget;import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;import com.xinxin.applicationtest.R;/*** Created by wxx on 2016/12/5  0005.* 作用 : 仿支付宝芝麻信用分*/public class IndicatorView extends View {private int sweepInWidth;//内圆弧宽度private int sweepOutWidth;//外圆弧宽度private int maxNum;//最大分值private int currentNum = 1;//当前分值private int startAngle;//圆弧开始的角度private int sweepAngle;//圆弧的结束的角度private int mWidth;//视图的宽private int mHeight;//视图的高private Paint paint;private Paint paint_2;private Paint paint_3;private Paint paint_4;private int radius;//圆弧半径public IndicatorView(Context context) {this(context, null);}public IndicatorView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);setBackgroundColor(0xFFFF6347);initAttr(attrs);initPaint();}private void initAttr(AttributeSet attributeSet) {TypedArray typedArray = getContext().obtainStyledAttributes(attributeSet, R.styleable.RoundIndicatorView);maxNum = typedArray.getInt(R.styleable.RoundIndicatorView_maxNum,500);startAngle = typedArray.getInt(R.styleable.RoundIndicatorView_startAngle, 160);sweepAngle = typedArray.getInt(R.styleable.RoundIndicatorView_sweepAngle, 220);sweepInWidth = dp2px(8);sweepOutWidth = dp2px(3);typedArray.recycle();}public int getCurrentNum() {return currentNum;}public void setCurrentNum(int currentNum) {this.currentNum = currentNum;invalidate();}public void setCurrentNumAnim(int num) {float duration = (float)Math.abs(num-currentNum)/maxNum *1500+500; //根据进度差计算动画时间ObjectAnimator anim = ObjectAnimator.ofInt(this,"currentNum",num);anim.setDuration((long) Math.min(duration,2000));anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {int value = (int) animation.getAnimatedValue();int color = calculateColor(value);setBackgroundColor(color);}});anim.start();}private int calculateColor(int value){setCurrentNum(value);ArgbEvaluator evealuator = new ArgbEvaluator();float fraction = 0;int color = 0;if(value <= maxNum/2){fraction = (float)value/(maxNum/2);color = (int) evealuator.evaluate(fraction,0xFFFF6347,0xFFFF8C00); //由红到橙}else {fraction = ( (float)value-maxNum/2 ) / (maxNum/2);color = (int) evealuator.evaluate(fraction,0xFFFF8C00,0xFF00CED1); //由橙到蓝}return color;}/*** 初始化所有画笔*/private void initPaint() {paint = new Paint(Paint.ANTI_ALIAS_FLAG);paint.setDither(true);paint.setStyle(Paint.Style.STROKE);paint.setColor(0xffffffff);paint_2 = new Paint(Paint.ANTI_ALIAS_FLAG);paint_3 = new Paint(Paint.ANTI_ALIAS_FLAG);paint_4 = new Paint(Paint.ANTI_ALIAS_FLAG);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);if (widthMode == MeasureSpec.EXACTLY) {mWidth = widthSize;} else {mWidth = dp2px(300);}if (heightMode == MeasureSpec.EXACTLY) {mHeight = heightSize;} else {mHeight = dp2px(400);}setMeasuredDimension(mWidth,mHeight);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.save();radius = getMeasuredWidth()/4;canvas.translate(mWidth /2, mHeight /2);drawRound(canvas);  //画内外圆弧drawScale(canvas);//画圆弧上的刻度drawIndicator(canvas);//画分值指示器drawCenterText(canvas);//画中间的字canvas.restore();}private String[] text ={"较差","中等","良好","优秀","极好"};/** 化圆弧上的刻度 */private void drawScale(Canvas canvas) {canvas.save();canvas.rotate(startAngle - 270);float count = (float)sweepAngle / 30;for (int i = 0; i <= 30; i++) {if (i % 6 == 0) {paint.setStrokeWidth(dp2px(3));canvas.drawLine(0, -radius - sweepInWidth / 2, 0, -radius + sweepInWidth / 2 + dp2px(2), paint);paint.setAlpha(0x90);drawText(canvas, String.valueOf(maxNum / 30 * i), paint);} else {paint.setStrokeWidth(dp2px(1));canvas.drawLine(0, -radius - sweepInWidth / 2, 0, -radius + sweepInWidth / 2, paint);paint.setAlpha(0x50);}if(i == 3 || i == 9 || i == 15 || i ==21 || i == 27) {drawText(canvas,text[(int)i/6],paint);}canvas.rotate(count);}canvas.restore();}/** 画刻度下方对应的分值 */private void drawText(Canvas canvas, String score, Paint paint) {paint.setStyle(Paint.Style.FILL);paint.setTextSize(dp2px(10));float width = paint.measureText(score);canvas.drawText(score,-width/2,-radius + sweepInWidth/2 + dp2px(15),paint);paint.setStyle(Paint.Style.STROKE);}private void drawRound(Canvas canvas) {//内圆canvas.save();paint.setAlpha(0x40);paint.setStrokeWidth(sweepInWidth);RectF rectf = new RectF(-radius,-radius,radius,radius);canvas.drawArc(rectf,startAngle,sweepAngle,false,paint);//外圆paint.setStrokeWidth(sweepOutWidth);int w = dp2px(10);RectF rectf2 = new RectF(-radius-w , -radius-w , radius+w , radius+w);canvas.drawArc(rectf2,startAngle,sweepAngle,false,paint);canvas.restore();}private int[] indicatorColor = {0xffffffff,0x00ffffff,0x99ffffff,0xffffffff};/** 画外边缘的分值指示器 */private void drawIndicator(Canvas canvas) {canvas.save();float sweep = (float) currentNum / (float) maxNum * sweepAngle;if(currentNum > maxNum) {sweep = sweepAngle;}SweepGradient sweepGradient = new SweepGradient(0, 0, indicatorColor, null);paint_2.setShader(sweepGradient);paint_2.setStyle(Paint.Style.STROKE);paint_2.setStrokeWidth(sweepOutWidth);int w = dp2px(10);RectF rectF = new RectF(-radius - w, -radius - w, radius + w, radius + w);canvas.drawArc(rectF,startAngle,sweep,false,paint_2);float x = (float) ((radius+dp2px(10))*Math.cos(Math.toRadians(startAngle+sweep)));float y = (float) ((radius+dp2px(10))*Math.sin(Math.toRadians(startAngle+sweep)));paint_3.setStyle(Paint.Style.FILL);paint_3.setColor(0xffffffff);paint_3.setMaskFilter(new BlurMaskFilter(dp2px(3), BlurMaskFilter.Blur.SOLID)); //需关闭硬件加速canvas.drawCircle(x,y,dp2px(3),paint_3);canvas.restore();}/** 画中间的字 */private void drawCenterText(Canvas canvas) {canvas.save();paint_4.setTextSize(radius/2);paint_4.setColor(0xffffffff);canvas.drawText(String.valueOf(currentNum),-paint_4.measureText(String.valueOf(currentNum))/2,0,paint_4);String content = "信用";if(currentNum < maxNum*1/5){content += text[0];}else if(currentNum >= maxNum*1/5 && currentNum < maxNum*2/5){content += text[1];}else if(currentNum >= maxNum*2/5 && currentNum < maxNum*3/5){content += text[2];}else if(currentNum >= maxNum*3/5 && currentNum < maxNum*4/5){content += text[3];}else if(currentNum >= maxNum*4/5){content += text[4];}paint_4.setTextSize(radius/4);Rect rect = new Rect();paint_4.getTextBounds(content,0,content.length(),rect);canvas.drawText(content,-rect.width()/2,rect.height(),paint_4);canvas.restore();}//一些工具方法protected int dp2px(int dp){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics());}protected int sp2px(int sp){return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());}
}

xml中引用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_credit_view"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"android:orientation="vertical"tools:context="com.xinxin.applicationtest.CreditViewActivity"><com.xinxin.applicationtest.widget.IndicatorViewandroid:id="@+id/viewOne"android:layout_width="wrap_content"android:background="@android:color/holo_blue_dark"android:layout_height="200dp" /><EditTextandroid:id="@+id/etScore"android:layout_width="match_parent"android:layout_height="wrap_content" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="start"/>
</LinearLayout>

如果使用

package com.xinxin.applicationtest;import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;import com.xinxin.applicationtest.widget.IndicatorView;public class CreditViewActivity extends AppCompatActivity {private IndicatorView viewOne;private EditText etScore;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_credit_view);viewOne = (IndicatorView)findViewById(R.id.viewOne);etScore = (EditText)findViewById(R.id.etScore);}public void start(View v) {String trim = etScore.getText().toString().trim();viewOne.setCurrentNumAnim(Integer.parseInt(trim));}
}

 

整理公司电脑,这开发过程中下载过很多的第三方库、demo啥玩意的,特别多,好几年了,电脑上到处都是一些第三方的代码,想着整理一下,清理清理没用的,所以基本都是把每一个demo都跑一下看看是什么东西,没用的就删了,发现了这个当时写的,觉得这个里边还有一些不错的view绘制的知识点和关键API,就写下来吧。

单看是不行的,需要参悟一下view绘制过程中的一些边、弧的算法。

还有一个是芝麻信用分分析图的 点击查看 https://blog.csdn.net/wxx_csdn/article/details/90714774

这篇关于自定义View,仿蚂蚁芝麻分仪表盘(早前的一版)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/223785

相关文章

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

基于Spring实现自定义错误信息返回详解

《基于Spring实现自定义错误信息返回详解》这篇文章主要为大家详细介绍了如何基于Spring实现自定义错误信息返回效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录背景目标实现产出背景Spring 提供了 @RestConChina编程trollerAdvice 用来实现 HTT

SpringSecurity 认证、注销、权限控制功能(注销、记住密码、自定义登入页)

《SpringSecurity认证、注销、权限控制功能(注销、记住密码、自定义登入页)》SpringSecurity是一个强大的Java框架,用于保护应用程序的安全性,它提供了一套全面的安全解决方案... 目录简介认识Spring Security“认证”(Authentication)“授权” (Auth

SpringBoot自定义注解如何解决公共字段填充问题

《SpringBoot自定义注解如何解决公共字段填充问题》本文介绍了在系统开发中,如何使用AOP切面编程实现公共字段自动填充的功能,从而简化代码,通过自定义注解和切面类,可以统一处理创建时间和修改时间... 目录1.1 问题分析1.2 实现思路1.3 代码开发1.3.1 步骤一1.3.2 步骤二1.3.3

dubbo3 filter(过滤器)如何自定义过滤器

《dubbo3filter(过滤器)如何自定义过滤器》dubbo3filter(过滤器)类似于javaweb中的filter和springmvc中的intercaptor,用于在请求发送前或到达前进... 目录dubbo3 filter(过滤器)简介dubbo 过滤器运行时机自定义 filter第一种 @A

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

SpringBoot 自定义消息转换器使用详解

《SpringBoot自定义消息转换器使用详解》本文详细介绍了SpringBoot消息转换器的知识,并通过案例操作演示了如何进行自定义消息转换器的定制开发和使用,感兴趣的朋友一起看看吧... 目录一、前言二、SpringBoot 内容协商介绍2.1 什么是内容协商2.2 内容协商机制深入理解2.2.1 内容

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06