这是在学习android的Canvas绘图技巧时做的一个实例。主要用的核心方法就是canvas.save,canvas.rotate,

canvas.translate以及canvas.restore。通过这个小例子的练习,可以更好的掌握这些方法的使用。

先贴一张最终的效果图吧,如下:

来一步一步的来写代码吧。新建一个项目,然后新建类MyView继承自View,下面我们来首先将外盘画出来。即最外面的那个

圆。代码如下:

 package com.example.testcanvas;

 import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.DragEvent;
import android.view.View;
/**
* 画一个仪表盘出来,哈哈
* @author fuly1314
*
*/
public class MyView extends View{ private int width;//view宽度
private int height;//view的高度
private int radius;//外层圆的半径 public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
} public MyView(Context context) {
super(context);
} protected void onDraw(Canvas canvas) { width = getWidth();
height = getHeight();
radius = width/2;//外部圆盘的半径 Paint paintCircle = new Paint();
paintCircle.setStyle(Paint.Style.STROKE);
paintCircle.setStrokeWidth(5);
paintCircle.setAntiAlias(true);
//画出外层的圆盘
canvas.drawCircle(width/2, height/2, radius, paintCircle); } }

代码很简单,相信这一步大家都不陌生。我们将圆形置在了屏幕的中心位置,并让半径为宽度的一半。其他的就不多说了。

接下来我们来画刻度值。

首先刻度值有两种,一种是大的刻度值,这类刻度值都是可以被6整除的,另外一类则不可以。这个在画的时候很容易解决。

不容易解决的是要按照一定的弧度来把刻度值给画上。如果在这个时候,不利用canvcas.rotate方法的话,简直是要愁死人了。

还好有这么一个方法可以很方便的解决这个问题。我们先看代码,然后再来详细解释。增加的代码如下:

package com.example.testcanvas;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.DragEvent;
import android.view.View;
/**
* 画一个仪表盘出来,哈哈
* @author fuly1314
*
*/
public class MyView extends View{ private int width;//view宽度
private int height;//view的高度
private int radius;//外层圆的半径
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
} public MyView(Context context) {
super(context);
} protected void onDraw(Canvas canvas) { width = getWidth();
height = getHeight();
radius = width/2;//外部圆盘的半径 Paint paintCircle = new Paint();
paintCircle.setStyle(Paint.Style.STROKE);
paintCircle.setStrokeWidth(5);
paintCircle.setAntiAlias(true);
//画出外层的圆盘
canvas.drawCircle(width/2, height/2, radius, paintCircle); /**
* 下面的代码要画出刻度值
*/ for(int i =0;i<24;i++)
{ Paint paintDegree = new Paint(); if(i%6 == 0)//画的是大的刻度值
{ paintDegree.setStrokeWidth(5);
paintDegree.setTextSize(30); canvas.drawLine(width/2, height/2-radius, width/2,
height/2-radius+60, paintDegree);
canvas.drawText(String.valueOf(i), width/2-paintDegree.measureText(String.valueOf(i))/2,
height/2-radius+90, paintDegree);
}else//画的是小刻度
{
paintDegree.setStrokeWidth(3);
paintDegree.setTextSize(25); canvas.drawLine(width/2, height/2-radius, width/2,
height/2-radius+30, paintDegree);
canvas.drawText(String.valueOf(i), width/2-paintDegree.measureText(String.valueOf(i))/2,
height/2-radius+60, paintDegree); } //将坐标系绕点(width/2,height/2)旋转15度
canvas.rotate(360/24, width/2, height/2); } } }

红色部分就是增加的画刻度线的代码。代码最核心的地方就是上面被黄色背景标注的地方。我们知道在画刻度的时候,刻度0是最好画的,如果

每一个刻度都能像画0刻度这么容易的话,岂不是太过瘾了!Android可谓在此时深深的了解你的愿望啊,于是Canvas.rotate方法就过来拯救你了!

你把一个圆分成了24份,每一份是15度,那么从画0刻度开始每次画一个刻度就把坐标系旋转15度,再来画下一个刻度,是不是就一直跟画0刻度的

方法是一样的了呢?显然是的!之所以应用rotate方法让坐标系围绕圆心旋转15度,可不就是为了这个嘛!因此你会发现在循环画刻度时,都是按照

画刻度0的画法来画的!!怎么样,神奇吧!至此,所有的刻度我们算是画好了。

最后我们来画两根指针。

再次修改代码如下:

 package com.example.testcanvas;

 import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.DragEvent;
import android.view.View;
/**
* 画一个仪表盘出来,哈哈
* @author fuly1314
*
*/
public class MyView extends View{ private int width;//view宽度
private int height;//view的高度
private int radius;//外层圆的半径
private int hcount = 0;
20 private int mcount = 0; public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
} public MyView(Context context) {
super(context);
} protected void onDraw(Canvas canvas) { width = getWidth();
height = getHeight();
radius = width/2;//外部圆盘的半径 Paint paintCircle = new Paint();
paintCircle.setStyle(Paint.Style.STROKE);
paintCircle.setStrokeWidth(5);
paintCircle.setAntiAlias(true);
//画出外层的圆盘
canvas.drawCircle(width/2, height/2, radius, paintCircle); /**
* 下面的代码要画出刻度值
*/ for(int i =0;i<24;i++)
{ Paint paintDegree = new Paint(); if(i%6 == 0)//画的是大的刻度值
{ paintDegree.setStrokeWidth(5);
paintDegree.setTextSize(30); canvas.drawLine(width/2, height/2-radius, width/2,
height/2-radius+60, paintDegree);
canvas.drawText(String.valueOf(i), width/2-paintDegree.measureText(String.valueOf(i))/2,
height/2-radius+90, paintDegree);
}else//画的是小刻度
{
paintDegree.setStrokeWidth(3);
paintDegree.setTextSize(25); canvas.drawLine(width/2, height/2-radius, width/2,
height/2-radius+30, paintDegree);
canvas.drawText(String.valueOf(i), width/2-paintDegree.measureText(String.valueOf(i))/2,
height/2-radius+60, paintDegree); } //将坐标系绕点(width/2,height/2)旋转15度
canvas.rotate(360/24, width/2, height/2); } canvas.save();//先保存下,因为下面要用到坐标的平移
86
87 //将坐标系的平移至原点为(wdith/2,height/2)的地方
88 canvas.translate(width/2, height/2);
89
90 int hourRadius = radius*2/4;
91 int minuteRaidus = radius*3/4;
92 int hx = (int) (hourRadius*Math.cos(hcount));
93 int hy = (int) (hourRadius*Math.sin(hcount));
94 int mx = (int) (minuteRaidus*Math.cos(mcount));
95 int my = (int) (minuteRaidus*Math.sin(mcount));
96
97 Paint paintHour = new Paint();
98 paintHour.setStrokeWidth(7);
99
100 canvas.drawLine(0, 0,hx , hy, paintHour);
101
102 Paint paintMinute = new Paint();
103 paintMinute.setStrokeWidth(3);
104
105 canvas.drawLine(0, 0, mx, my, paintMinute);
106
107 canvas.restore();
108
109
110 mcount++;
111
112 if(mcount%10 == 0){
113 hcount++;
114 }
115
116 postInvalidateDelayed(500); } }

核心代码就是黄色背景标注的代码!因为在画指针的时候,我们发现还是不爽,还有从屏幕左上角来计算坐标。所以就使用canvas.translate方法

直接将坐标系给平移了。直接平移到圆心,因为我们的出发点就在圆形。接下来是不是画那些指针就十分容易了!在这里,我们使用了两个变量来控制

指针的转动分别是hcount和mcount。在转动的过程中怎么确定指针的坐标呢?画个图来说明吧。如下:

代码中的求指针的坐标的时候就是按照这个思路来求的。相信上面的代码应该没有什么问题了吧。当然了,代码写的乱,有很多可以优化的时候。

这里只是为了练习下canvas的方法,不去深究了。最后别忘记调用postInvalidateDelayed方法来进行刷新。

至此,这个能动的仪表盘就做好了。下面把它放进布局中吧。修改activity_main.xml代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
> <com.example.testcanvas.MyView
android:layout_width="match_parent"
android:layout_height="match_parent"
/> </RelativeLayout>

直接运行程序吧!效果跟上面的贴图一样。

android之旋转的刻度盘的更多相关文章

  1. Android立体旋转动画实现与封装(支持以X、Y、Z三个轴为轴心旋转)

    本文主要介绍Android立体旋转动画,或者3D旋转,下图是我自己实现的一个界面 立体旋转分为以下三种: 1. 以X轴为轴心旋转 2. 以Y轴为轴心旋转 3. 以Z轴为轴心旋转--这种等价于andro ...

  2. Android 屏幕旋转 处理 AsyncTask 和 ProgressDialog 的最佳方案

    的最佳方案 标签: Android屏幕旋转AsyncTaskProgressDialog 2014-07-19 09:25 39227人阅读 评论(46) 收藏 举报 分类: [android 进阶之 ...

  3. android 屏幕旋转

    转自:http://blog.csdn.net/oyzhizhong/article/details/8131799 屏是LANDSCAPE的,要让它默认显示为PORTRAIT. 1.kernel里要 ...

  4. android手机旋转屏幕时让GridView的列数与列宽度自适应

    无意中打开了一年前做过的一个android应用的代码,看到里面实现的一个小功能点(如题),现写篇文章做个笔记.当时面临的问题是,在旋转屏幕的时候需要让gridview的列数与宽度能自适应屏幕宽度,每个 ...

  5. 【Android】[转] Android屏幕旋转使用OrientationEventListener的监听

    说明 遇到一个奇葩的问题,我在使用onConfigChanged拦截屏幕的横竖屏旋转时,发现直接进行180度的横屏/竖屏转换居然没有反应!查找原因发现仅对landscape或者portrait状态有用 ...

  6. Android中轴旋转特效实现,制作别样的图片浏览器

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/10766017 Android API Demos中有很多非常Nice的例子,这些例 ...

  7. Android图片旋转,缩放,位移,倾斜,对称完整示例(一)——imageView.setImageMatrix(matrix)和Matrix

    MainActivity如下: import android.os.Bundle; import android.view.MotionEvent; import android.view.View; ...

  8. Android开发 旋转屏幕导致Activity重建解决方法(转)

     文章来源:http://www.jb51.net/article/31833.htm Android开发文档上专门有一小节解释这个问题.简单来说,Activity是负责与用户交互的最主要机制,任何“ ...

  9. Android屏幕旋转

    一个手机最基本的旋转方向有上面4种,而在Android开发中,涉及到屏幕旋转的地方很多,而且各个函数给出的角度值都不一样,比如 Activity的getRotate,Camera的setDisplay ...

随机推荐

  1. MySQL安全问题(防范必知)

    对于任何一种数据库来说,安全问题都是非常重要的.如果数据库出现安全漏洞,轻则数据被窃取,重则数据被破坏,这些后果对于一些重要的数据库都是非常严重的.下面来从操作系统和数据库两个层对MySQL的安全问题 ...

  2. Android 学习笔记之网络通信基础+WebView....

    PS:加快学习进度...下周一完成Android网络通信...然后正式进入实战... 学习内容: 1.Android中Http基础... 2.Android中的Socket基础... 3.Androi ...

  3. IOS开发UI基础UISegment属性

    UISegment属性 1.segmentedControlStyle设置segment的显示样式.typedef NS_ENUM(NSInteger, UISegmentedControlStyle ...

  4. Redis设计与实现-内部数据结构篇

    题记:这本书是2015年11月份开始读的,大约花了一个多月的时间通读了一遍,最近由于需要对redis做一些深入的了解,因此又花了两个多月仔细精读了一遍,由于本书设计的内容较多,且每部分的内容都比较细致 ...

  5. VS2010 根据模型生成数据库 打开edmx.sql文件时 vs出现无响应的解决方案

    今天在VS2010 sp1+sql server 2008 R2+Win7操作系统下测试ADO.NET 实体数据模型时 ,遇到这样一个问题. 首先建好实体模型,然后"根据模型生成数据库&qu ...

  6. [moka同学笔记]linux服务器防火墙的设置

    网站突然打不开:服务器停止了,重启后,防火墙自动启动,导致网站打不开. 1.查看防火墙 systemctl status firewalld 2.关闭防火墙 systemctl stop firewa ...

  7. Python on VS Code

    install python extension Press F1, and input "ext install python". Then the icon at the le ...

  8. Verilog学习笔记设计和验证篇(一)...............总线和流水线

    总线 总线是运算部件之间数据流通的公共通道.在硬线逻辑构成的运算电路中只要电路的规模允许可以比较自由的确定总线的位宽,从而大大的提高数据流通的速度.各个运算部件和数据寄存器组可以通过带有控制端的三态门 ...

  9. phpcms—— 内容中的附件调用和添加远程地址的调用

    phpcms中几个地址调用的方法 1,CSS路径有{CSS_PATH}2,图片路径有{IMG_PATH}3,JS路径有{JS_PATH} 4,那么附件的路径如何调用,使用下面的方式可以得到附件的路径前 ...

  10. 搭建angularjs API文档站点

    提供一个国内可以访问的 angularjs API文档站点 http://i.frllk.com/ 文档直接在 github 上下载的: https://github.com/angular-cn/n ...