先上效果图

一、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. Vue组件通讯

    Vue最常用的组件通讯有三种:父->子组件通讯.子->父组件通讯,兄弟组件通讯.(template用的pug模板语法) 1.父->子组件通讯 父->子组件通讯,是通过props ...

  2. html5 css选择器 井号, 句点的区别

    一.理解CSS的样式组成CSS里的样式表是有规则组成的,每条规则有三个部分组成:1.选择器(如下面例子中的:"body"),告诉浏览器文档的哪个部分受规则影响:2.属性(如实例中的 ...

  3. WebService发布与调用问题:expected: {http://schemas.xmlsoap.org/soap/envelope/}Envelope but found: {http://schemas.xmlsoap.org/wsdl/}definitions

    Mailbox===AsYVzdwoY_b6uD s>>>>>>>javax.xml.ws.Service@103bf65 hs>>>> ...

  4. Maximum Product Subarray 最大连续乘积子集

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  5. Bitmap到底占多少内存

    转至:Android 开发绕不过的坑:你的 Bitmap 究竟占多大内存? Bugly 技术干货系列内容主要涉及移动开发方向,是由 Bugly 邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟 ...

  6. 关于App的cpu/内存/流量 /电量的方法(GT工具)

    https://mp.weixin.qq.com/s?__biz=MzUzNTQxMzMzMg==&mid=2247484376&idx=1&sn=651e9cf22801b5 ...

  7. Linux扩展根目录下的空间

    自己通过root创建了一个新用户,然而当我使用这个新用户时发现,/home/my中的空间只有几十M,完全不能满足我的使用,所以通过下面的方法扩展根下的空间. 我的本次操作,参考于 http://www ...

  8. 对数损失函数(Logarithmic Loss Function)的原理和 Python 实现

    原理 对数损失, 即对数似然损失(Log-likelihood Loss), 也称逻辑斯谛回归损失(Logistic Loss)或交叉熵损失(cross-entropy Loss), 是在概率估计上定 ...

  9. 初识WCF1

    参照: http://blog.csdn.net/songyefei/article/details/7363296 第一篇 Hello WCF WCF(Windows Communication F ...

  10. Sqlserver函数基础使用

    函数基本功能: 转换工厂日期,将8点20之前的时间转化为前一天的时间. if exists (select * from sysobjects where xtype='fn' and name='F ...