先上效果图

一、View的测量(刻度盘的大小测量)

  在现实生活中,我们如果要去画一个图形,那么便要知道它的大小和位置。所以android绘图时需要我们对view进行测量。android为我们提供了onMeasure()方法来帮助我们去测量一个view,我们只需要重写onMeasur()方法,将我们测算长宽设置给setMeasuredDimension()。

     @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//根据模式测算长宽
... setMeasuredDimension(width,height);
}

  我们首先测量我们最开始弧形的大小。即图中的样例。

  

  @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//根据模式测算长宽,这里获取的尺寸便是在xml文件中指定的尺寸
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
//以最小值为刻度区域正方形的长
len = Math.min(width, height);
//确定圆弧所在的矩形区域
oval = new RectF(0, 0, len, len);
radius = len/2;
//设置测量高度和宽度
setMeasuredDimension(len,len);
}

二、View的绘制(简单绘制出我们需要的弧形)

测算完成后我们需要将他在画面上显示出来,android为我们提供了onDraw()方法,来绘制view。

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
     //弧形的绘画查看api
canvas.drawArc(oval,startAngle,sweepAngle,useCenter,paint); }

不了解canvas的可以去看看canvas的绘制API

现在在布局文件中设置后,就可以看见我们最开始的view了。

三、完善我们的绘制,为仪表盘添加刻度。

    private void drawViewLine(Canvas canvas) {
canvas.save();
//移动canvas
canvas.translate(radius,radius);
//旋转canvas
canvas.rotate(30);
//普通刻度
Paint linePatin=new Paint();
//设置普通刻度画笔颜色
linePatin.setColor(Color.WHITE);
//线宽
linePatin.setStrokeWidth(2);
//设置画笔抗锯齿
linePatin.setAntiAlias(true);
/* //画一条刻度线
canvas.drawLine(0,radius,0,radius-40,linePatin);*/
//画101条刻度线
//确定每次旋转的角度
float rotateAngle=sweepAngle/99;
//绘制需要有颜色部分的画笔
Paint targetLinePatin=new Paint();
targetLinePatin.setColor(Color.GREEN);
targetLinePatin.setStrokeWidth(2);
targetLinePatin.setAntiAlias(true);
//记录已经绘制过的有色部分范围(角度float)
float hasDraw=0;
for(int i=0;i<100;i++){
if (hasDraw <= targetAngle && targetAngle != 0) {
//计算已经绘制的比例
canvas.drawLine(0, radius, 0, radius - 40, targetLinePatin);
} else {
canvas.drawLine(0,radius,0,radius-40,linePatin);
}
hasDraw += rotateAngle;
canvas.rotate(rotateAngle);
} //操作完成后恢复状态
canvas.restore();
}

 如图

四、完善onMeasure()测量

  我们先看看在布局中的CircleView

  原先

<com.example.tyr.circleviewtest.CircleView
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

  如图

  

  改成Button

  <Button
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

  现在,我么修改CircleView改为wrap_content,如图

  可以发现没有改变

  对比button的wrap_content可以发现如图,

  

  所以我们需要在onMeasure()方法中,对view的模式进行区别测量。

五、MeasureSpec类

  android系统为我们提供了一个短小精悍的类MeasureSpec。它是一个32位的int值,高两位为测量模式,低30位为测量大小。

  测量模式分为三种:

  1、EXACTLY--系统的默认模式。

      精确模式,当我们将width和height指定100dp、200dp等精确值时或是match_parent属性时系统使用EXACTLY模式

  2、AT_MOST

    最大值模式,当height和width属性指定为wrap_content时,控件大小随子控件或内容的变化而变化,控件大小只要不超过父控件允许的最大尺寸即可。

  3、UNSPECIFIED

      不指定大小测量模式,view想多大就多大,通常在绘制自定义view时才会用。

   将onMeasure()方法进行修改,适应wrap_content

 @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//根据模式测算长宽
int width = measureSize(widthMeasureSpec);
int height = measureSize(heightMeasureSpec);
//以最小值为刻度区域正方形的长
len = Math.min(width, height);
//确定圆弧所在的矩形区域
oval = new RectF(0, 0, len, len);
radius = len/2;
//设置测量高度和宽度
setMeasuredDimension(len, len);
} private int measureSize(int measureSpec){
     //差不多固定的格式
int reslut = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
  
if (specMode==MeasureSpec.EXACTLY){
reslut = specSize;
}else{
reslut = 200;
if (specMode==MeasureSpec.AT_MOST){
reslut = Math.min(reslut,specSize);
}
} return reslut;
}

 

六、自定义属性

  我们在xml文件中使用的时候往往会使用一些属性类似width和height等等,那么我们便需要为我们的刻度盘添加新的属性。

<resources>
<declare-styleable name="CircleView">
<attr name="pointDisArc" format="dimension"></attr>
<attr name="textSize" format="dimension"></attr>
</declare-styleable>
</resources>

在构造方法中处理

 public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
parseAttr(context, attrs, defStyleAttr);
initPaint();
} private void parseAttr(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.CircleView,defStyleAttr,0);
pDisArc = typedArray.getDimensionPixelSize(R.styleable.CircleView_pointDisArc,dp2px(context,20));
textSize = typedArray.getDimensionPixelSize(R.styleable.CircleView_textSize,dp2px(context,20));
typedArray.recycle();
}
  <com.example.tyr.circleviewtest.CircleView
android:id="@+id/cicleview"
android:layout_width="match_parent"
android:layout_height="match_parent"
circle:textSize="20sp"
circle:pointDisArc="20dp"
/>

到目前为止view的自定义差不多完成了,也可以将刻度盘设计的更加精巧一些,下一节开始viewgroup的绘制,涉及到新的方法onLayout()。

DEMO

自定义view(结合刻度盘学习)的更多相关文章

  1. Android自定义View初步

    经过上一篇的介绍,大家对于自定义View一定有了一定的认识,接下来我们就以实现一个图片下显示文字的自定义View来练习一下.废话不多说,下面进入我们的正题,首先看一下我们的思路,1.我们需要通过在va ...

  2. 通过圆形载入View了解自定义View

    这是自定义View的第一篇文章,通过制作简单的自定义View来了解自定义View的流程. 自定义View是Android学习和开发中必不可少的一部分.通过自定义View我们可以制作丰富绚丽的控件,自定 ...

  3. Android查缺补漏(View篇)--自定义 View 的基本流程

    View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以 ...

  4. 简单说说Android自定义view学习推荐的方式

    这几天比较受关注,挺开心的,嘿嘿. 这里给大家总结一下学习自定义view的一些技巧.  以后写自定义view可能不会写博客了,但是可以开源的我会把源码丢到github上我的地址:https://git ...

  5. 20170831工作日记--自定义View学习

    学习了LayoutInflater的原理分析.视图的绘制流程.视图的状态及重绘等知识,按类型来划分的话,自定义View的实现方式大概可以分为三种,自绘控件.组合控件.以及继承控件.那么下面我们就来依次 ...

  6. Android之自定义View学习(一)

    Android之自定义View学习(一) Canvas常用方法: 图片来源 /** * Created by SiberiaDante on 2017/6/3. */ public class Bas ...

  7. Android开发之制作圆形头像自定义View,直接引用工具类,加快开发速度。带有源代码学习

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 QQ986945193 博客园主页:http://www.cnblogs.com/mcxiaobing ...

  8. salesforce 零基础学习(五十)自定义View或者List以及查看系统原来的View或者List

    salesforce给我们提供了标准的页面,比如标准的页面包括标准的列表和标准的详细页视图.有的时候我们想要自定义视图,比如做一个项目的时候不希望使用者直接通过ID查看到标准的详细页,而是跳转到指定处 ...

  9. Android自定义View学习(四)

    硬件加速 参考:HenCoder Android 自定义 View 1-8 硬件加速 硬件加速能够让绘制变快,主要有三个原因: 本来由 CPU 自己来做的事,分摊给了 GPU 一部分,自然可以提高效率 ...

随机推荐

  1. 事件处理程序DOM0,DOM2,IE的区别总结

    一.事件流   顺序 备注 事件冒泡 目标对象~document对象   事件捕获 document对象~目标对象 老版本浏览器不支持 DOM事件流 document对象~目标对象~document对 ...

  2. CSS实现太极图(1个div实现)

    使用一个div实现太极图的步骤如下: HTML部分: <body> <div class="box-taiji"> </div> </bo ...

  3. JavaScript自定义字符串格式化

    在JS中没有字符串拼接的方法,如过要使用怎么办呢?这时我们可以通过字符串的prototype可以自定义方法. <script> String.prototype.format = func ...

  4. EasyNetQ简单使用

    class Program { static void Main(string[] args) { //打开消息确认机制 using (var bus = RabbitHutch.CreateBus( ...

  5. 让UpdatePanel支持文件上传(2):服务器端组件 .

    我们现在来关注服务器端的组件.目前的主要问题是,我们如何让页面(事实上是ScriptManager控件)认为它接收到的是一个异步的回送?ScriptManager控件会在HTTP请求的Header中查 ...

  6. Python学习---Django路由系统【all】

    Django URL (路由系统) Django URL (路由系统): URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL模式以及要为该URL模式调用的视图函数之间的映 ...

  7. ZT I Believe I Can Fly(我相信我能飞)

    I Believe I Can Fly(我相信我能飞) 歌手:R. Kelly(罗 凯利) 歌词部分 I used to think that I could not go on 我原以为我无法坚持下 ...

  8. 树-二叉搜索树-AVL树

    树-二叉搜索树-AVL树 树 树的基本概念 节点的度:节点的儿子数 树的度:Max{节点的度} 节点的高度:节点到各叶节点的最大路径长度 树的高度:根节点的高度 节点的深度(层数):根节点到该节点的路 ...

  9. 虚拟机下的CentOS无法上网的解决办法

    1.首先保证虚拟机的网络适配器为NAT模式 2.设置虚拟机的“编辑”-->“虚拟网络编辑器”中的VMnet8的DHCP的设置两个选项都勾选上. 3.设置物理主机,保证虚拟网关的IP地址为自动获取 ...

  10. Vue-Router基础使用

    作为Vue生态系统里面的一大成员,Vue-Router主要负责vue中的页面路由及其传值问题. 1.基本使用–添加路由 基本使用主要包括四个部分,页面引入.配置路由数组.实例化路由.把实例化的路由加入 ...