自定义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

相关文章

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

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

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla

MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)

1、MVC MVC(Model-View-Controller) 是一种常用的架构模式,用于分离应用程序的逻辑、数据和展示。它通过三个核心组件(模型、视图和控制器)将应用程序的业务逻辑与用户界面隔离,促进代码的可维护性、可扩展性和模块化。在 MVC 模式中,各组件可以与多种设计模式结合使用,以增强灵活性和可维护性。以下是 MVC 各组件与常见设计模式的关系和作用: 1. Model(模型)

HTML5自定义属性对象Dataset

原文转自HTML5自定义属性对象Dataset简介 一、html5 自定义属性介绍 之前翻译的“你必须知道的28个HTML5特征、窍门和技术”一文中对于HTML5中自定义合法属性data-已经做过些介绍,就是在HTML5中我们可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,例如我们要在一个文字按钮上存放相对应的id: <a href="javascript:" d

一步一步将PlantUML类图导出为自定义格式的XMI文件

一步一步将PlantUML类图导出为自定义格式的XMI文件 说明: 首次发表日期:2024-09-08PlantUML官网: https://plantuml.com/zh/PlantUML命令行文档: https://plantuml.com/zh/command-line#6a26f548831e6a8cPlantUML XMI文档: https://plantuml.com/zh/xmi

argodb自定义函数读取hdfs文件的注意点,避免FileSystem已关闭异常

一、问题描述 一位同学反馈,他写的argo存过中调用了一个自定义函数,函数会加载hdfs上的一个文件,但有些节点会报FileSystem closed异常,同时有时任务会成功,有时会失败。 二、问题分析 argodb的计算引擎是基于spark的定制化引擎,对于自定义函数的调用跟hive on spark的是一致的。udf要通过反射生成实例,然后迭代调用evaluate。通过代码分析,udf在

鸿蒙开发中实现自定义弹窗 (CustomDialog)

效果图 #思路 创建带有 @CustomDialog 修饰的组件 ,并且在组件内部定义controller: CustomDialogController 实例化CustomDialogController,加载组件,open()-> 打开对话框 , close() -> 关闭对话框 #定义弹窗 (CustomDialog)是什么? CustomDialog是自定义弹窗,可用于广告、中

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD