自定义表盘(未彻底完成)
2016-12-01 17:41
120 查看
看到大家都在自定义view玩。我也来玩一下,其实自定义View,画图不难,难的是数据的计算。如果你要做一个可扩展的View,里面的数据肯定是要灵活可变的。
这个时候,你就不可以把数据写死。下面是我自定义的View。
首先要搞清楚Canvas绘图的角度计算。0刻度不是在上方。Canvas里面的画弧度的起始度数(0)是以钟表的三点钟为0刻度的。
所以,第一步是要画3/4的圆弧的表盘。
/**
* 绘制表盘
*
* @param canvas
*/
private void drawPlate(Canvas canvas, RectF oval) {
//开始画表盘,仪表盘不是一个完整的圆,是3/4的圆,所以起始度数是134度,结束点是44(404)度。
for (int i = 134; i < 405; i += (270 / scales.length)) {
canvas.drawArc(oval, i, 2, false, paint);
//最后一个连结弧不要
if (i + 270 / scales.length < 405) {
canvas.drawArc(oval, i + 4, 270 / scales.length - 6, false, paint);
}
}
}
其中指针是一个只有2°的弧。其中数组scales为仪表盘的刻度数值,可以自定义。
绘制了表盘之后,开始绘制表盘指针读数,比如汽车读数为50的时候,应该是怎么样的。
/**
* 绘制读数
*
* @param canvas
*/
private void drawRegistration(Canvas canvas, RectF oval) {
// 用来更改值,判断是否是动画
int prog = isStartCartoom ? cartoomProgress : polluteNum;
/*开始画读数颜色*/
int index_pro = getProIndex(prog);//当前所处的段位,比如100,在默认数据中属于第二段。101属于第三段
int start_degrees = 138;//开始画颜色的起始度数
float rotation = 0f;//指针偏转角度
Log.e("info", "prog=" + prog);
Log.e("info", "index_pro=" + index_pro);
for (int i = 0; i < index_pro; i++) {
int d_value = i == 0 ? scales[0] : scales[i] - scales[i - 1];
num_paint.setColor(colors[i % colors.length]);// 设置圆环的颜色
int end1 = prog < scales[i] ? i == 0 ? prog : prog - scales[i - 1] : d_value;
end1 = end1 * (270 / scales.length - 6) / d_value;// 算出来画的角度
canvas.drawArc(oval, start_degrees, end1, false, num_paint);
rotation = start_degrees + 90 + end1;
start_degrees += 45;
}
if (contains(prog)) {
rotation = 225 + (270 / scales.length) * (index_pro - 1);
Log.e("info", "rotation=" + rotation);
}
//指针
drawPointer(canvas, rotation);
}
/**
* 绘制指针
*
* @param canvas
* @param rotation
*/
private void drawPointer(Canvas canvas, float rotation) {
// 用来更改值,判断是否是动画
int prog = isStartCartoom ? cartoomProgress : polluteNum;
//圆心X的坐标
int centre = getWidth() / 2;
int radius = (int) (centre - roundWidth / 2); // 圆环的半径
float scaleX = defaultWidth / width;
float scaleY = defaultHeight / height;
//表盘指针
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.chart_index);
/* 控制旋转 */
Matrix matrix = new Matrix();
/**
* 开始画指针
*/
float sx = (float) ((getWidth() / bitmap.getWidth()) * 0.8);
matrix.setScale(sx, sx);
matrix.setRotate(rotation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
canvas.drawBitmap(bitmap, (radius - bitmap.getWidth() / 2) + 10 * scaleX, radius - bitmap.getHeight() / 2 + 10 * scaleY,
new Paint());
bitmap.recycle();
float text_size = text_paint.measureText(String.valueOf(prog));
text_paint.setColor(colors[getProIndex(prog) % colors.length]);
canvas.drawText(String.valueOf(prog), radius - text_size / 2, centre + bitmap.getHeight() / 2 + 30, text_paint);
}
当前最不可少的当然需要一个动画了。没有动画怎么都感觉不好看。
通过Timer来实现的动画,你也可以通过轻量级的异步线程AsyncTask来实现
class CartoomEngine {
public Handler mHandler;
public boolean mBCartoom; // 是否正在作动画
public Timer mTimer; // 用于作动画的TIMER
public MyTimerTask mTimerTask; // 动画任务
public int mTimerInterval; // 定时器触发间隔时间(ms)
public float mCurFloatProcess; // 作动画时当前进度值
@SuppressLint("HandlerLeak")
public CartoomEngine() {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case TIMER_ID: {
if (mBCartoom == false) {
return;
}
mCurFloatProcess += 1;
setCartoomProgress((int) mCurFloatProcess);
if (mCurFloatProcess >= polluteNum) {
stopCartoom();
}
}
break;
}
}
};
mBCartoom = false;
mTimer = new Timer();
mTimerInterval = 5;
mCurFloatProcess = 0;
}
public synchronized void startCartoom(int time) {
if (time <= 0 || mBCartoom == true) {
return;
}
mBCartoom = true;
isStartCartoom = true;
setCartoomProgress(0);
mCurFloatProcess = 0;
mTimerTask = new MyTimerTask();
mTimer.schedule(mTimerTask, 0, mTimerInterval);
}
public synchronized void stopCartoom() {
if (mBCartoom == false) {
return;
}
mBCartoom = false;
setNum(polluteNum);
isStartCartoom = false;
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
}
private final static int TIMER_ID = 0x0010;
class MyTimerTask extends TimerTask {
@Override
public void run() {
Message msg = mHandler.obtainMessage(TIMER_ID);
msg.sendToTarget();
}
}
}完整的代码链接在代码片里 https://code.csdn.net/snippets/2022443
指针图片在附件里
这个时候,你就不可以把数据写死。下面是我自定义的View。
首先要搞清楚Canvas绘图的角度计算。0刻度不是在上方。Canvas里面的画弧度的起始度数(0)是以钟表的三点钟为0刻度的。
所以,第一步是要画3/4的圆弧的表盘。
/**
* 绘制表盘
*
* @param canvas
*/
private void drawPlate(Canvas canvas, RectF oval) {
//开始画表盘,仪表盘不是一个完整的圆,是3/4的圆,所以起始度数是134度,结束点是44(404)度。
for (int i = 134; i < 405; i += (270 / scales.length)) {
canvas.drawArc(oval, i, 2, false, paint);
//最后一个连结弧不要
if (i + 270 / scales.length < 405) {
canvas.drawArc(oval, i + 4, 270 / scales.length - 6, false, paint);
}
}
}
其中指针是一个只有2°的弧。其中数组scales为仪表盘的刻度数值,可以自定义。
绘制了表盘之后,开始绘制表盘指针读数,比如汽车读数为50的时候,应该是怎么样的。
/**
* 绘制读数
*
* @param canvas
*/
private void drawRegistration(Canvas canvas, RectF oval) {
// 用来更改值,判断是否是动画
int prog = isStartCartoom ? cartoomProgress : polluteNum;
/*开始画读数颜色*/
int index_pro = getProIndex(prog);//当前所处的段位,比如100,在默认数据中属于第二段。101属于第三段
int start_degrees = 138;//开始画颜色的起始度数
float rotation = 0f;//指针偏转角度
Log.e("info", "prog=" + prog);
Log.e("info", "index_pro=" + index_pro);
for (int i = 0; i < index_pro; i++) {
int d_value = i == 0 ? scales[0] : scales[i] - scales[i - 1];
num_paint.setColor(colors[i % colors.length]);// 设置圆环的颜色
int end1 = prog < scales[i] ? i == 0 ? prog : prog - scales[i - 1] : d_value;
end1 = end1 * (270 / scales.length - 6) / d_value;// 算出来画的角度
canvas.drawArc(oval, start_degrees, end1, false, num_paint);
rotation = start_degrees + 90 + end1;
start_degrees += 45;
}
if (contains(prog)) {
rotation = 225 + (270 / scales.length) * (index_pro - 1);
Log.e("info", "rotation=" + rotation);
}
//指针
drawPointer(canvas, rotation);
}
/**
* 绘制指针
*
* @param canvas
* @param rotation
*/
private void drawPointer(Canvas canvas, float rotation) {
// 用来更改值,判断是否是动画
int prog = isStartCartoom ? cartoomProgress : polluteNum;
//圆心X的坐标
int centre = getWidth() / 2;
int radius = (int) (centre - roundWidth / 2); // 圆环的半径
float scaleX = defaultWidth / width;
float scaleY = defaultHeight / height;
//表盘指针
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.chart_index);
/* 控制旋转 */
Matrix matrix = new Matrix();
/**
* 开始画指针
*/
float sx = (float) ((getWidth() / bitmap.getWidth()) * 0.8);
matrix.setScale(sx, sx);
matrix.setRotate(rotation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
canvas.drawBitmap(bitmap, (radius - bitmap.getWidth() / 2) + 10 * scaleX, radius - bitmap.getHeight() / 2 + 10 * scaleY,
new Paint());
bitmap.recycle();
float text_size = text_paint.measureText(String.valueOf(prog));
text_paint.setColor(colors[getProIndex(prog) % colors.length]);
canvas.drawText(String.valueOf(prog), radius - text_size / 2, centre + bitmap.getHeight() / 2 + 30, text_paint);
}
当前最不可少的当然需要一个动画了。没有动画怎么都感觉不好看。
通过Timer来实现的动画,你也可以通过轻量级的异步线程AsyncTask来实现
class CartoomEngine {
public Handler mHandler;
public boolean mBCartoom; // 是否正在作动画
public Timer mTimer; // 用于作动画的TIMER
public MyTimerTask mTimerTask; // 动画任务
public int mTimerInterval; // 定时器触发间隔时间(ms)
public float mCurFloatProcess; // 作动画时当前进度值
@SuppressLint("HandlerLeak")
public CartoomEngine() {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case TIMER_ID: {
if (mBCartoom == false) {
return;
}
mCurFloatProcess += 1;
setCartoomProgress((int) mCurFloatProcess);
if (mCurFloatProcess >= polluteNum) {
stopCartoom();
}
}
break;
}
}
};
mBCartoom = false;
mTimer = new Timer();
mTimerInterval = 5;
mCurFloatProcess = 0;
}
public synchronized void startCartoom(int time) {
if (time <= 0 || mBCartoom == true) {
return;
}
mBCartoom = true;
isStartCartoom = true;
setCartoomProgress(0);
mCurFloatProcess = 0;
mTimerTask = new MyTimerTask();
mTimer.schedule(mTimerTask, 0, mTimerInterval);
}
public synchronized void stopCartoom() {
if (mBCartoom == false) {
return;
}
mBCartoom = false;
setNum(polluteNum);
isStartCartoom = false;
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
}
private final static int TIMER_ID = 0x0010;
class MyTimerTask extends TimerTask {
@Override
public void run() {
Message msg = mHandler.obtainMessage(TIMER_ID);
msg.sendToTarget();
}
}
}完整的代码链接在代码片里 https://code.csdn.net/snippets/2022443
指针图片在附件里
相关文章推荐
- Android 自定义View 实现表盘效果
- 自定义View基础篇——表盘
- 自定义view完成简单的小游戏----手指兔子
- Ubuntu 11.10彻底卸载 UNITY和UNITY 2D,安装配置GMONE3 Classic,自定义面板
- VBA学习7_VBA自定义工作表函数不能完成的任务
- 项目应用:使用自定义注解完成对controller的aop控制
- 对于c#中,在完成自定义用户控件然后重新生成无效的可能解决办法。
- 通过自定义特性,使用EF6拦截器完成创建人、创建时间、更新人、更新时间的统一赋值(了解下EF不常见的技术点)
- 通过自定义特性,使用EF6拦截器完成创建人、创建时间、更新人、更新时间的统一赋值(使用数据库服务器时间赋值,接上一篇)
- 完成你的自定义JSP Tag标签-Basic Coustom Tag
- QuickXDev增强功能:用户自定义变量、函数自动完成提示及转到定义
- YII2中自定义用户认证模型,完成登陆和注册
- android 自定义 view 实现表盘效果
- 如何使用JW Player来播放Flash并隐藏控制按钮和自定义播放完成后执行的JS
- Elasticsearch自定义脚本完成性能测试
- 完成你的自定义JSP Tag标签-Basic Coustom Tag
- 自定义View-汽车表盘
- android自定义表盘
- 自定义view之二时钟表盘
- 自定义表盘,一个是关于canvas.rotate的运用,一个是关于Path,Math的运用