自定义仪表盘笔记
来源:互联网 发布:软件系统设计实例 编辑:程序博客网 时间:2024/06/06 02:48
参考自:http://blog.csdn.net/vv_bug/article/details/71694562
1.新建DashboardView类继承View,一些准备工作
public class DashboardView extends View{ //弧形开始的角度 private static final int startAngle = 180; //弧面所跨的弧度 private static final int sweepAngle = 180; //里面数字的单位 private static final String unint = "mmhg"; //每隔多少画一个刻度 private static final int angPre = 2; //总刻度 private static final int totalDial = 90; //进度条的底色 private static final int PROGRESS_COLOR = 0x55000000; //画普通的线用的笔 private Paint linePaint; //画文字用的笔 private Paint textPaint; //画进度条用的笔 private Paint progressPaint; //里面半圆的半径 private int innerRadius = dp2px(100); //最内层的padding private int innerPadding = dp2px(6); //外两层的padding private int outerPadding = dp2px(10); //进度条的宽度 private int progressLineW = dp2px(8); //最里面跟最外面的线的宽度 private int innerLineWidth = dp2px(1); //刻度线的宽度 private int outerLineWidth = dp2px(2); //刻度线的高度 private int outerLineHeight = dp2px(10); //文字的size private float textSize = sp2px(18); //单位文字的size private float textSizeUnit = sp2px(13); //当前进度 private float currProgress = 0.5f; //起始值 private float start = 0; //最终值 private float end = 150; public DashboardView(Context context) { this(context, null); } public DashboardView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public DashboardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); obtainAttributes(attrs); } /** * 获取自定义的属性 */ private void obtainAttributes(AttributeSet attrs) { init(); } /** * 初始化 */ private void init() { linePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); linePaint.setStyle(Paint.Style.STROKE); linePaint.setColor(Color.WHITE); progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setColor(Color.WHITE); progressPaint.setStrokeWidth(progressLineW); progressPaint.setStrokeCap(Paint.Cap.ROUND); textPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); textPaint.setStyle(Paint.Style.STROKE); textPaint.setColor(Color.WHITE); textPaint.setTextSize(textSize); }}
然后先是onMeasure
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //最里面圆的半径计算 //半径=控件的宽度/2-最里层的padding-刻度线的高度-里第二层的padding-进度条的宽度-第二层padding-最外层线宽度 innerRadius = getMeasuredWidth() / 2 - innerPadding - outerLineHeight - outerPadding - progressLineW - outerPadding - innerLineWidth; //因为view的设置的高度是wrap_content,所以我们要重新计算高度 //高度=刻度线的高度+padding+最里面一层的半径+padding+进度条宽度+padding+最外层线宽度 int height = (outerLineHeight + innerPadding + innerRadius + outerPadding + progressLineW + outerPadding + innerLineWidth); //重新生成高度 heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
然后是onDraw
@Overrideprotected void onDraw(Canvas canvas) { drawInnerArc(canvas); }
画最里层的圆弧
*先定义一个矩形,矩形其实为一个圆的大小
*画圆弧 180度开始 到 360度结束 这样就有一个半圆
private void drawInnerArc(Canvas canvas) { //定义一个矩形区域 RectF rectF = new RectF(); int width = getWidth(); //矩形的top为 padding + 刻度线的高度+padding+进度条宽度 +padding +最外层弧线线宽度 //left为控件的宽度/2 - 半圆半径 int top = outerLineHeight + innerPadding + innerLineWidth + outerPadding * 2 + progressLineW; rectF.set(width / 2 - innerRadius, top, width / 2 + innerRadius, top + innerRadius * 2); linePaint.setStrokeWidth(innerLineWidth); //弧线的起始位置为180度的位置,扫过的弧度为180 canvas.drawArc(rectF, startAngle, sweepAngle, false, linePaint);}
看下效果
然后画刻度
*用角度的方法来画,利用三角函数算出刻度两端的点的值
*算出来的以圆弧的中心点的坐标系,真正的坐标系为左上角,所以还要加上getWidth()/2或者getHeight()
private void drawDial(int startAngle, int allAngle, int dialCount, int per, int longLength, int shortLength, int radius, Canvas canvas) { linePaint.setStrokeWidth(outerLineWidth); int length; int angle; //根据需要显示的刻度总个数遍历 for (int i = 0; i <= dialCount; i++) { //每一个刻度对应的起始角度为180度+(总度数/个数)*对应刻度的位置 angle = (int) ((allAngle) / (dialCount * 1f) * i) + startAngle; //线条的起始点位置 int[] startP; //线条的end点的位置 int[] endP; //当i%per==0,每一个需要显示短刻度的时候(因为设计稿第一个为短的刻度条) if (i % per == 0) { //短刻度条的长度为长刻度条的一半 length = shortLength; //获取刻度条起始点位置 startP = getPointFromAngleAndRadius(angle, radius - length); endP = getPointFromAngleAndRadius(angle, radius - length * 2); } else { length = longLength; startP = getPointFromAngleAndRadius(angle, radius); endP = getPointFromAngleAndRadius(angle, radius - length); } //画出对应的刻度条 canvas.drawLine(startP[0], startP[1], endP[0], endP[1], linePaint); }}/** * 根据刻度条相应的角度算出点位置 * @param angle * @param radius * @return */private int[] getPointFromAngleAndRadius(int angle, int radius) { //根据三角函数公式可以知道,横坐标值为(刻度条+innnerradius)也就是刻度条对应圆的半径 //乘以一个cos(angle),因为我们是以(getWidth() / 2,控件的高度)位置建的坐标系 //而真正的坐标系的位置为控件左上角,所以算出的值后需要+getWidth() / 2或者getHeight() double x = radius * Math.cos(angle * Math.PI / 180) + getWidth() / 2; double y = radius * Math.sin(angle * Math.PI / 180) + getHeight(); return new int[]{(int) x, (int) y};}
看下效果
接下来画文字
主要是确定文字的位置
private void drawText(Canvas canvas) { //当前文字对应的值为(0+(150-0)*当前进度) String currText = String.valueOf((int) (start + (end - start) * currProgress)); //因为数字字体大而单位数字小 textPaint.setTextSize(textSize); //测量数字文字对应的长度 float numWidth = textPaint.measureText(currText); //重新设置笔的size textPaint.setTextSize(textSizeUnit); //为了获取单位文字的高度 Rect rect = new Rect(); //获取单位文字的最小矩形范围 textPaint.getTextBounds(unint, 0, unint.length(), rect); //单位文字的宽度 float unitWidth = textPaint.measureText(unint); //从新设置笔的大小 textPaint.setTextSize(textSize); //文字的basex为(控件的宽度/2-(数字文字的长度+单位文字的长度)/2) float baseX = getWidth()/2 - (unitWidth + numWidth) / 2; //文字的centery为(最外层线的宽度+padding+进度条宽度+padding+padding+最里面半圆半径的一半) float centerY = innerLineWidth + outerPadding + progressLineW + outerPadding + outerLineHeight + innerPadding + innerRadius / 2; //(主要解决文字在半圆的中心文字)根据centery算出文字的basey float baseY = centerY - (textPaint.ascent() + textPaint.descent()) / 2; //设置数字文字为粗体 textPaint.setFakeBoldText(true); //画出数字文字 canvas.drawText(currText + "", baseX, baseY, textPaint); //重新设置画笔 textPaint.setTextSize(textSizeUnit); textPaint.setFakeBoldText(false); //画出单位文字(跟数字文字底部有一个偏移量所以basey-了一个(单位文字的高度的1/6)) canvas.drawText(unint, baseX + numWidth + dp2px(1), baseY - rect.height() / 6, textPaint);}
看下效果
画出最外面的弧线跟进度条
*画弧的时候,弧的画笔宽度的一半会和矩形相切
private void drawOuterStaticLine(Canvas canvas) { //最外层的弧线 RectF rectF1 = new RectF(); int width = getWidth(); rectF1.set(innerLineWidth, innerLineWidth, width - innerLineWidth, getHeight() * 2 - innerLineWidth); linePaint.setStrokeWidth(innerLineWidth); canvas.drawArc(rectF1, startAngle, sweepAngle, false, linePaint); //静态的进度条 progressPaint.setColor(PROGRESS_COLOR); RectF rectF2 = new RectF(); rectF2.set(innerLineWidth + outerPadding + outerPadding / 2, innerLineWidth + outerPadding + outerPadding / 2, width - (innerLineWidth + outerPadding + outerPadding / 2), getHeight() * 2 - ((innerLineWidth + outerPadding + outerPadding / 2))); canvas.drawArc(rectF2, startAngle, sweepAngle, false, progressPaint);}
看下效果
最后就是设置进度的方法了
public void setProgress(float progress){ if (currProgress == progress) { return; } this.currProgress = progress; if (Looper.myLooper() == Looper.getMainLooper()) { invalidate(); } else { postInvalidate(); }}
测试
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#a7ff0000" android:gravity="center_horizontal" android:orientation="vertical"> <com.lzz.dashboard.DashboardView android:id="@+id/dashboardView" android:background="@color/colorAccent" android:layout_marginTop="40dp" android:layout_marginLeft="40dp" android:layout_marginRight="40dp" android:layout_width="match_parent" android:layout_height="wrap_content"/></LinearLayout>
public class MainActivity extends AppCompatActivity { DashboardView dashboardView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dashboardView = (DashboardView) findViewById(R.id.dashboardView); startAni(); } private void startAni() { //对应dashboardView中的setProgress()方法 ObjectAnimator a= ObjectAnimator.ofFloat(dashboardView,"progress",0f,1f); a.setInterpolator(new AccelerateDecelerateInterpolator()); a.setDuration(3000); a.setRepeatCount(ValueAnimator.INFINITE); a.setRepeatMode(ValueAnimator.REVERSE); a.start(); }}
阅读全文
0 0
- 自定义仪表盘笔记
- 自定义仪表盘
- 自定义Wordpress的仪表盘
- 自定义仪表盘DashBoard - -kankanstyle
- 自定义之仪表盘
- 自定义wordpress仪表盘
- WordPress自定义仪表盘
- 自定义仪表盘PaneView
- 自定义仪表盘控件
- Android自定义仪表盘视图
- Android自定义仪表盘
- Android自定义仪表盘
- 自定义汽车仪表盘
- Android 自定义仪表盘
- 时尚仪表盘 Android 自定义View
- Android自定义View之仪表盘
- 自定义View 汽车速度仪表盘
- 仪表盘 网速测试 自定义view
- C语言中static全局变量与普通的全局变量的区别
- 《sar访谈》-linux命令五分钟系列之二十九
- intellij idea tomcat jsp 热部署
- gcc生成静态库和动态库
- 频率域低通滤波
- 自定义仪表盘笔记
- 推荐一个好的验证码MvcCaptcha
- JAVA编写一个程序从网上下载一张图片
- python 中的var()函数和cov函数用法
- Hadoop之MapReduce原理
- 欢迎使用CSDN-markdown编辑器
- phpcms后台登陆验证码显示异常
- TortoiseSVN安装使用
- Deep Learning with PyTorch: A 60 Minute Blitz 要点整理