自定义仪表盘PaneView
1、概述
最近学习自定义View,趁着周末做了一个仪表盘练练手,效果还可以,在此分享一下先上效果图(截图有点不清晰,凑合着看下吧)
项目在我的github上https://github.com/xsfelvis/PanelView
有图才能有真相,下面简要说一下如何实现的
2、实现
【分析有哪些属性需要】
在values/attr文件中进行声明,这些属性都是可以在xml中进行使用的,实现定制的,比如unit单位属性
<resources>
<declare-styleable name="PanelView">
<attr name="arcColor" format="color"/>
<attr name="arcWidth" format="dimension"/>
<attr name="secArcWidth" format="dimension"/>
<attr name="android:text"/>
<attr name="tikeCount" format="integer"/>
<attr name="pointerColor" format="color"/>
<attr name="Unit" format="string"/>
<attr name="android:textSize"/>
<attr name="AcrStartColor" format="color"/>
<attr name="AcrEndColor" format="color"/>
<attr name="textColor" format="color"/>
</declare-styleable>
</resources>
然后为了结构上更加工整,推荐单独写一个文件来处理这些属性,最好不要和自定义控件混在一起
这里在PanelViewAttr.java中做了处理
package PanelView;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import com.xsf.panelview.R;
import util.PxUtils;
/**
* Created by hzxushangfei on 2016/1/23.
*/
public class PanelViewAttr {
private int mArcColor;
private int mPointerColor;
private int mTikeCount;
private int mTextSize;
private String mText = "";
private int arcwidth;
private int mScendArcWidth;
private String unit;//单位
private int acrStartColor;
private int acrEndColor;
private int textColor;
public PanelViewAttr(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PanelView, defStyleAttr, 0);
mArcColor = ta.getColor(R.styleable.PanelView_arcColor, context.getResources().getColor(R.color.colorPrimaryDark));
mPointerColor = ta.getColor(R.styleable.PanelView_pointerColor, context.getResources().getColor(R.color.PointerColor));
mTikeCount = ta.getInt(R.styleable.PanelView_tikeCount, 12);
mTextSize = ta.getDimensionPixelSize(PxUtils.spToPx(R.styleable.PanelView_android_textSize, context), 24);
mText = ta.getString(R.styleable.PanelView_android_text);
arcwidth = ta.getInt(R.styleable.PanelView_arcWidth, 3);
mScendArcWidth = ta.getInt(R.styleable.PanelView_secArcWidth, 50);
unit = ta.getString(R.styleable.PanelView_Unit);
acrStartColor = ta.getColor(R.styleable.PanelView_AcrStartColor, context.getResources().getColor(R.color.GREEN));
acrEndColor = ta.getColor(R.styleable.PanelView_AcrEndColor, context.getResources().getColor(R.color.RED));
textColor = ta.getColor(R.styleable.PanelView_textColor, context.getResources().getColor(R.color.Yellow));
ta.recycle();
}
public int getAcrEndColor() {
return acrEndColor;
}
public int getAcrStartColor() {
return acrStartColor;
}
public int getArcwidth() {
return arcwidth;
}
public int getmArcColor() {
return mArcColor;
}
public int getmPointerColor() {
return mPointerColor;
}
public int getmTikeCount() {
return mTikeCount;
}
public int getmTextSize() {
return mTextSize;
}
public String getmText() {
return mText;
}
public int getmScendArcWidth() {
return mScendArcWidth;
}
public String getUnit() {
return unit;
}
public int getTextColor() {
return textColor;
}
}
再然后在自定义view实现类 PanelView.java中获取
panelViewattr = new PanelViewAttr(context, attrs, defStyleAttr);
通过get方法获取
mArcColor = panelViewattr.getmArcColor();
mPointerColor = panelViewattr.getmPointerColor();
mTikeCount = panelViewattr.getmTikeCount();
mTextSize = panelViewattr.getmTextSize();
mTextColor = panelViewattr.getTextColor();
mText = panelViewattr.getmText();
mArcWidth = panelViewattr.getArcwidth();
mScendArcWidth = panelViewattr.getmScendArcWidth();
unit = panelViewattr.getUnit();
acrStartColor = panelViewattr.getAcrStartColor();
acrEndColor = panelViewattr.getAcrEndColor();
OK,这些都是小儿科,主要看onMeasure和OnDraw()方法
这里主要对exactly做了处理,其余的按照统一处理onMeasure()方法如下,推荐用一个方法来处理measure,不要把宽和高都写一遍,这样代码看起来会有点冗杂
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int realWidth = startMeasure(widthMeasureSpec);
int realHeight = startMeasure(heightMeasureSpec);
setMeasuredDimension(realWidth, realHeight);
}
private int startMeasure(int msSpec) {
int result = 0;
int mode = MeasureSpec.getMode(msSpec);
int size = MeasureSpec.getSize(msSpec);
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = PxUtils.dpToPx(200, mContext);
}
//Log.d("xsf", "startMeasure " + result);
return result;
}
onMeasure之后决定了大小,重头戏在onDraw,直接看onraw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float percent = mPercent / 100f;
//最外面线条
drawOutAcr(canvas);
//绘制刻度
drawerNum(canvas);
//绘制粗圆弧
drawInArc(canvas, percent);
//绘制中间小圆和圆环
drawInPoint(canvas);
//绘制指针
drawerPointer(canvas, percent);
//绘制矩形和文字
drawerRecAndText(canvas, percent);
}
这样写是不是显得逻辑非常清楚,不要把细节都放在ondraw方法中,用一个个函数封装是最好不过的了
首先 drawOutAcr(canvas)
画最外面的弧
private void drawOutAcr(Canvas canvas) {
//最外面线条
rectF1 = new RectF(mArcWidth, mArcWidth, getWidth() - mArcWidth, getHeight() - mArcWidth);
canvas.drawArc(rectF1, START_ARC, DURING_ARC, false, paintOuter_Arc);
}
主要使用到canvas.drawArc方法,没啥好说的
执行完你会看到一个弧
然后是画刻度drawerNum(canvas);
这个函数开始画刻度和数字
private void drawerNum(Canvas canvas) {
canvas.save(); //记录画布状态
canvas.rotate(-(180 - START_ARC + 90), getWidth() / 2, getHeight() / 2);
float rAngle = DURING_ARC / mTikeCount;
for (int i = 0; i < mTikeCount + 1; i++) {
canvas.save(); //记录画布状态
canvas.rotate(rAngle * i, getWidth() / 2, getHeight() / 2);
canvas.drawLine(getWidth() / 2, mArcWidth, getWidth() / 2, 20, paintOuter_Arc);//画刻度线
canvas.drawText("" + i * 10, getWidth() / 2 - mArcWidth * 2, 40, paintouter_Num);//画刻度
canvas.restore();
}
canvas.restore();
}
要点:canvas.save 和canvas.restore来记录和恢复画布的状态
结合canvas.ratate旋转画布,画布旋转固定角度,画笔此时不需要变化,大大方便,这个技巧需要掌握
此时画出
然后执行drawInArc(canvas, percent);画粗圆弧
private void drawInArc(Canvas canvas, float percent) {
rectF2 = new RectF(mArcWidth + OFFSET, mArcWidth + OFFSET, getWidth() - mArcWidth - OFFSET, getHeight() - mArcWidth - OFFSET);
canvas.drawArc(rectF2, START_ARC, DURING_ARC, false, paintInerArc);
rectF3 = new RectF(mArcWidth + OFFSET, mArcWidth + OFFSET, getWidth() - mArcWidth - OFFSET, getHeight() - mArcWidth - OFFSET);
shader = new LinearGradient(mArcWidth + OFFSET, mArcWidth + OFFSET,
getWidth() - mArcWidth - OFFSET, getHeight() - mArcWidth - OFFSET, acrStartColor, acrEndColor, Shader.TileMode.REPEAT);
paintInerArc_tranform.setShader(shader);
canvas.drawArc(rectF3, START_ARC, <span style="color:#000099;">percent * DURING_ARC</span>, false, paintInerArc_tranform);
}
这个涉及到了粗圆弧颜色状态的变化,首先画一个白色的圆弧,画笔设置粗一点,为白色
然后使用shader来变色,在相同的圆弧上根据百分比再覆盖一层颜色,我们画弧是从150度(START_ARC)为开始位置,持续了240度(DURING_ARC)
此时状态为
然后开始画圆环和圆点这个比较简单,注意下圆环使用空心画笔,圆点使用实心画笔即可
private void drawInPoint(Canvas canvas) {
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mMinRingRadius, paintOuter_Arc);//中心小圆环
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mMinCircleRadius, paint_centerPoint_Pointer);//中心圆点
}
圆弧颜色变化解决了,下面来解决指针跟随百分比变化
percent在0-1之间,实现-120- +120变化(DURING_ARC=240),那么转化成数学关系就是,变化角度angle = DURING_ARC*(percent-0.5),ok表达式搞定就好搞了
private void drawerPointer(Canvas canvas, float percent) {
canvas.save();
float angel = DURING_ARC * (percent - 0.5f);
canvas.rotate(angel, getWidth() / 2, getHeight() / 2);//指针与外弧边缘持平
paint_centerPoint_Pointer.setStrokeWidth(mArcWidth);
canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2 - mArcWidth * 2 - OFFSET - mScendArcWidth, paint_centerPoint_Pointer);
canvas.restore();
}
根据百分比变化位置的指针也画出来了
最后画画文字和单位
private void drawerRecAndText(Canvas canvas, float percent) {
float length = 0;
paint_text.setTextSize(mTextSize);
length = paint_text.measureText(mText);
canvas.drawText(mText, getWidth() / 2 - length / 2, (float) (getHeight() / 2 * (1 + Math.sqrt(2) / 3)), paint_text);
paint_text.setTextSize(mTextSize * 1.5f);
speed = StringUtil.floatFormat(120 * percent) +<span style="color:#336666;"> unit</span>;
length = paint_text.measureText(speed);
canvas.drawText(speed, getWidth() / 2 - length / 2, (float) (getHeight() / 2 * (1 + Math.sqrt(2) / 2)), paint_text);
}
为了使文字画在中间需要使用path里面的measureText的方法,然后为了文字和速度字体有层次感,这里设置为文字的1.5倍大小
ok很简答吧!
自定义仪表盘PaneView的更多相关文章
- IOS自定义仪表盘
登录|注册 周海锋 的专栏 Objective-C/Cocos2d/Cocos2d-x/Php/JS 目录视图 摘要视图 订阅 2016软考项目经理实战班 学院周年礼-顶 ...
- Android 中自定义仪表盘
如图: 自定义属性 values文件下添加 attrs.xml文件 <?xml version="1.0" encoding="utf-8"?> & ...
- WPF自定义仪表盘控件
闲来无事,分享一个仪表盘 源码: 直接复制代码即可运行,=.=! <Window x:Class="TGP.InstrumentationDemo.MainWindow" x ...
- 黄聪:定制化WordPress后台自定义仪表盘
WordPress作为一博客管理系统,相对来说已经相当简洁了,对用户也十分友好,新手也极易上手. 仪表盘是我们登陆WordPress后看到的后台界面,映入眼帘的是各种各样的信息,如WordPress ...
- Cloud Insight 仪表盘上线 | 全面监控 Redis
OneAPM 作为应用性能领域的新兴领军企业,近期发布了重量级新产品-- Cloud Insight 数据管理平台,用它能够监控所有基础组件,并通过 tag 标签对数据进行管理. 近日,Cloud I ...
- Android 自定义View -- 简约的折线图
转载请注明出处:http://write.blog.csdn.net/postedit/50434634 接上篇 Android 圆形百分比(进度条) 自定义view 昨天分手了,不开心,来练练自定义 ...
- ELK学习实验009:安装kibana的仪表盘
一 metricbeat仪表盘 1.1 安装metricbeat仪表盘 可以将metricbeat数据在kibana中展示 [root@node4 ~]# cd /usr/local/metricbe ...
- CODING 仪表盘功能正式推出,实现工作数据可视化!
CODING 仪表盘功能现已正式推出!该功能旨在用一张张统计卡片的形式,统计并展示使用 CODING 中所产生的数据.这意味着无需额外的设置,就可以收集归纳宝贵的工作数据并予之量化分析.这些海量的数据 ...
- 简单4步,利用Prometheus Operator实现自定义指标监控
本文来自Rancher Labs 在过去的文章中,我们花了相当大的篇幅来聊关于监控的话题.这是因为当你正在管理Kubernetes集群时,一切都会以极快的速度发生变化.因此有一个工具来监控集群的健康状 ...
随机推荐
- 用Python最原始的函数模拟eval函数的浮点数运算功能(2)
这应该是我编程以来完成的难度最大的一个函数了.因为可能存在的情况非常多,需要设计合理的参数来控制解析流程.经验概要: 1.大胆假设一些子功能能够实现,看能否建立整个框架.如果在假设的基础上都无法建立, ...
- Spark Scheduler模块源码分析之TaskScheduler和SchedulerBackend
本文是Scheduler模块源码分析的第二篇,第一篇Spark Scheduler模块源码分析之DAGScheduler主要分析了DAGScheduler.本文接下来结合Spark-1.6.0的源码继 ...
- Android快速关联V4包的方式
很多时候需要管理v4包,当然有很多种办法去关联.本人觉得最快速的方式,是通过添加配置文件的方式.只需要ctrl+c和ctrll+v就能解决了 方法如下: 1.新建一个android-support-v ...
- 剑指offer面试题6 重建二叉树(c)
- FFmpeg源代码简单分析:av_write_trailer()
===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...
- Cocos2D实现上下滚动式状态窗口
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 有时候要显示的内容太多,我们无法在iOS设备的小屏幕上显示出来 ...
- jsp中文乱码 Servlet中文乱码 utf-8
JSP+Servlet项目中,项目统一使用utf-8编码.配置过滤器过滤所以请求并设置utf-8编码,jsp页面也都设置utf-8,但是还有一点很容易忽视的就是tomcat也要设置utf-8,默认情况 ...
- Google会思考的深度学习系统
上周五在旧金山举行的机器学习会议上,Google软件工程师Quoc V. Le讲解了Google的"深度学习"系统是如何运作的. "深度学习"需要用到大型计算机 ...
- Intellij IDEA插件开发入门
现今的IDE尽管有如"洪水猛兽"般强大,但要知道再强大的IDE也没法提供给使用者想要的一切功能, 所以IDE一般都提供有API接口供开发者自行扩展.下面以Intellij IDEA ...
- 压力测试工具Ab简介
Apache安装包中自带的压力测试工具 Apache Benchmark(简称ab) 简单易用,这里就采用 ab作为压力测试工具了. 1.独立安装 通过 yum-utils中的yumdownload ...