上篇介绍了自定义控件的一个简单案例,本篇文章主要介绍如何给自定义控件自定义一些属性。

Android 中使用自定义属性的一般步骤:

  1. 定义declare-styleable,添加attr
  2. 使用TypedArray获取自定义属性
  3. 设置到View上

自定义属性都存在于/value/attr.xml文件中,以如下格式存在

  1. <resource>
  2. <declare-styleable name="自定义属性名称">
  3.  
  4. <attr name="属性名称" format="属性种类"/>
  5.  
  6. ......
  7.  
  8. </declare-styleable>
  9.  
  10. </resource>

format属性值:

  • reference:引用资源

  • string:字符串

  • Color:颜色

  • boolean:布尔值

  • dimension:尺寸值

  • float:浮点型

  • integer:整型

  • fraction:百分数

  • enum:枚举类型

  • flag:位或运算

代码说话:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <declare-styleable name="CircularAttrsView">
  4. <!--圆形绘制的位置-->
  5. <attr name="circular_circle_gravity">
  6. <flag name="left" value="0"/>
  7. <flag name="top" value="1"/>
  8. <flag name="center" value="2"/>
  9. <flag name="right" value="3"/>
  10. <flag name="bottom" value="4"/>
  11. </attr>
  12.  
  13. <attr name="circular_circle_radius" format="dimension"/><!--圆形半径-->
  14. <attr name="circular_circle_progress" format="integer"/><!--当前进度值-->
  15. <attr name="circular_progress_color" format="color"/><!--进度显示颜色-->
  16. <attr name="circular_background_color" format="color"/><!--圆形背景色-->
  17. </declare-styleable>
  18. </resources>

使用属性

  1. <com.zhangqie.customcontrol.demo2.CircularAttrsView
  2. android:layout_width="300dp"
  3. android:layout_height="300dp"
  4. android:background="#e4e4e4"
  5. zq:circular_background_color="@color/colorAccent"
  6. zq:circular_circle_gravity="center"
  7. zq:circular_circle_progress="30"
  8. zq:circular_progress_color="@color/colorPrimary"
  9. zq:circular_circle_radius="50dp"
  10. android:layout_margin="5dp"
  11. android:padding="10dp"
  12. />

上面zq:这个可以随便去,只有相同就行

接下来就是获取属性,并使用或设置属性

  1. public class CircularAttrsView extends View {
  2.  
  3. /****
  4. * 有三个参数的构造函数中第三个参数是默认的Style,
  5. * 这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style,且只有在明确调用的时候才会生效,
  6. */
  7.  
  8. private final static String TAG = CircularAttrsView.class.getName();
  9.  
  10. private Paint mPaint;
  11. private int backgroundColor = Color.GRAY;
  12. private int progressColor = Color.BLUE;
  13. private float radius;
  14. private float progress;
  15.  
  16. private float centerX = 0;
  17. private float centerY = 0;
  18. public static final int LEFT = 0;
  19. public static final int TOP = 1;
  20. public static final int CENTER = 2;
  21. public static final int RIGHT = 3;
  22. public static final int BOTTOM = 4;
  23.  
  24. private int gravity = CENTER;
  25.  
  26. private RectF rectF;
  27.  
  28. public CircularAttrsView(Context context) {
  29. super(context);
  30. init();
  31. }
  32.  
  33. public CircularAttrsView(Context context, AttributeSet attrs) {
  34. super(context, attrs);
  35. initParams(context,attrs);
  36. }
  37.  
  38. public CircularAttrsView(Context context, AttributeSet attrs, int defStyleAttr) {
  39. super(context, attrs, defStyleAttr);
  40. initParams(context,attrs);
  41. }
  42.  
  43. private void init(){
  44. mPaint = new Paint();
  45. mPaint.setAntiAlias(true);
  46. }
  47.  
  48. private void initParams(Context context,AttributeSet attrs){
  49. mPaint = new Paint();
  50. mPaint.setAntiAlias(true);
  51. rectF = new RectF();
  52. /***
  53. * 每一个属性集合编译之后都会对应一个styleable对象,通过styleable对象获取TypedArray typedArray,
  54. * 然后通过键值对获取属性值,这点有点类似SharedPreference的取法。
  55. */
  56. TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircularAttrsView);
  57. if (typedArray != null){
  58. backgroundColor = typedArray.getColor(R.styleable.CircularAttrsView_circular_background_color,Color.GRAY);
  59. progressColor = typedArray.getColor(R.styleable.CircularAttrsView_circular_progress_color,Color.BLUE);
  60. radius = typedArray.getDimension(R.styleable.CircularAttrsView_circular_circle_radius,0);
  61. progress = typedArray.getInt(R.styleable.CircularAttrsView_circular_circle_progress,0);
  62. gravity = typedArray.getInt(R.styleable.CircularAttrsView_circular_circle_gravity,CENTER);
  63. Log.e(TAG,backgroundColor+"--"+progressColor+"--"+radius+"--"+progress+"--"+gravity);
  64. typedArray.recycle();
  65. }
  66. }
  67.  
  68. /****
  69. * 测量-Measure过程是计算视图大小
  70. *
  71. * @param widthMeasureSpec
  72. * @param heightMeasureSpec
  73. */
  74. @Override
  75. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  76. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  77.  
  78. //根据提供的测量值(格式)提取模式(三个模式之一)
  79. //MeasureSpec有3种模式分别是UNSPECIFIED, EXACTLY和AT_MOST,
  80. int widthMode = MeasureSpec.getMode(widthMeasureSpec); //取出宽度的测量模式
  81. int widthSize = MeasureSpec.getSize(widthMeasureSpec);//获取View的大小(宽度的确切数值)
  82.  
  83. int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  84. int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  85.  
  86. Log.i(TAG,"onMeasure---widthMode--->"+widthMode);
  87. switch (widthMode){
  88. case MeasureSpec.EXACTLY:
  89.  
  90. break;
  91. case MeasureSpec.AT_MOST:
  92.  
  93. break;
  94. case MeasureSpec.UNSPECIFIED:
  95.  
  96. break;
  97. }
  98. Log.i(TAG,"onMeasure--widthSize--->"+ widthSize);
  99. Log.i(TAG,"onMeasure--heightMode-->"+ heightMode);
  100. Log.i(TAG,"onMeasure--heightSize-->"+heightSize);
  101.  
  102. int width = getWidth();
  103. int height = getHeight();
  104. Log.e(TAG, "onDraw---->" + width + "*" + height);
  105.  
  106. centerX = width / 2;
  107. centerY = width / 2;
  108. switch (gravity){
  109. case LEFT:
  110. centerX = radius + getPaddingLeft();
  111. break;
  112. case TOP:
  113. centerY = radius + getPaddingTop();
  114. break;
  115. case CENTER:
  116. break;
  117. case RIGHT:
  118. centerX = width - radius - getPaddingRight();
  119. break;
  120. case BOTTOM:
  121. centerY = height - radius - getPaddingBottom();
  122. break;
  123. }
  124.  
  125. float left = centerX - radius;
  126. float top = centerY - radius;
  127. float right = centerX + radius;
  128. float bottom = centerY + radius;
  129. rectF.set(left,top,right,bottom);
  130. }
  131.  
  132. /***
  133. * 确定View的大小(这个函数在视图大小发生改变时调用。)
  134. *
  135. * 宽度,高度,上一次宽度,上一次高度。
  136. * 只需关注 宽度(w), 高度(h) 即可,这两个参数就是View最终的大小。
  137. * @param w
  138. * @param h
  139. * @param oldw
  140. * @param oldh
  141. */
  142. @Override
  143. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  144. super.onSizeChanged(w, h, oldw, oldh);
  145. Log.i(TAG,"onSizeChanged");
  146. }
  147.  
  148. /****
  149. * 布局-Layout过程用于设置视图在屏幕中显示的位置,onLayout一般只会在自定义ViewGroup中才会使用
  150. *
  151. * 确定布局的函数是onLayout,它用于确定子View的位置,在自定义ViewGroup中会用到,他调用的是子View的layout函数。
  152. *
  153. * @param changed
  154. * @param left
  155. * @param top
  156. * @param right
  157. * @param bottom
  158. */
  159. @Override
  160. protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  161. super.onLayout(changed, left, top, right, bottom);
  162. Log.i(TAG,"onLayout");
  163. }
  164.  
  165. /***
  166. * 绘制-draw过程主要用于利用前两步得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作
  167. * @param canvas
  168. */
  169. @Override
  170. protected void onDraw(Canvas canvas) {
  171. super.onDraw(canvas);
  172. mPaint.setColor(backgroundColor);
  173. // FILL填充, STROKE描边,FILL_AND_STROKE填充和描边
  174. mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
  175.  
  176. canvas.drawCircle(centerX,centerY,radius,mPaint);//画圆
  177. mPaint.setColor(progressColor);
  178.  
  179. double percent = progress * 1.0 / 100;
  180. int angle = (int)(percent * 360);
  181. //根据进度画圆弧
  182. canvas.drawArc(rectF,270,angle,true,mPaint);
  183. }
  184. }

效果图:(居中的,可以通过  zq:circular_circle_gravity="center"  来设置显示的位置)

源码地址:https://github.com/DickyQie/android-custom-control

android--------自定义控件 之 属性篇的更多相关文章

  1. Android - 自定义控件和属性(attr和TypedArray)

    http://blog.csdn.net/zjh_1110120/article/details/50976027 1.attr format 取值类型 以ShapeView 为例 <decla ...

  2. Android自定义控件(36篇)

    http://blog.csdn.net/lmj623565791/article/details/44278417 http://download.csdn.net/user/lmj62356579 ...

  3. Android自定义控件系列之应用篇——圆形进度条

    一.概述 在上一篇博文中,我们给大家介绍了Android自定义控件系列的基础篇.链接:http://www.cnblogs.com/jerehedu/p/4360066.html 这一篇博文中,我们将 ...

  4. android 自定义控件(初篇)

    android 自定义控件 在写UI当中很多时候会用到自定义的控件,其实自定义控件就像是定义一个类进行调用就OK了.有些相关的感念可以查看API 下面就用个简单的例子来说明自定义控件: public ...

  5. Android自定义控件之自定义组合控件

    前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发 ...

  6. Android自定义控件之自定义属性

    前言: 上篇介绍了自定义控件的基本要求以及绘制的基本原理,本篇文章主要介绍如何给自定义控件自定义一些属性.本篇文章将继续以上篇文章自定义圆形百分比为例进行讲解.有关原理知识请参考Android自定义控 ...

  7. Android自定义控件之基本原理

    前言: 在日常的Android开发中会经常和控件打交道,有时Android提供的控件未必能满足业务的需求,这个时候就需要我们实现自定义一些控件,今天先大致了解一下自定义控件的要求和实现的基本原理. 自 ...

  8. Android自定义控件1

    概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...

  9. 一起来学习Android自定义控件1

    概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...

  10. [Xamarin.Android] 自定义控件

    [Xamarin.Android] 自定义控件 前言 软件项目开发的过程中,免不了遇到一些无法使用内建控件就能满足的客户需求,例如:时速表.折线图...等等.这时开发人员可以透过自定义控件的方式,为项 ...

随机推荐

  1. Derek解读Bytom源码-启动与停止

    作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...

  2. Gym 100247B Similar Strings(哈希+思维)

    https://vjudge.net/problem/Gym-100247B 题意: 如果两个字符串通过映射后是一样的,则说明这两个字符串是相似的,现在给出n个字符串,计算出有多少组字符串是相似的. ...

  3. c#四舍五入取整

    Math.Round(3.45, 0, MidpointRounding.AwayFromZero) 上取整或下取整 Math.Ceiling(3.1)=4; Math.Floor(3.9)=3;

  4. 【Python】【异步IO】

    # [[异步IO]] # [协程] '''协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在 ...

  5. 【Selenium2】【项目实战】

    [public/login.py] from selenium import webdriverfrom selenium.webdriver.common.by import Byimport ti ...

  6. 网站项目所有js css无法引用问题解决方案

    网站页面中的所有js css引用失效,路径确保正确,但是浏览器就是报找不到引用.仔细查找发现问题所在: 报错信息很详细了,就是.NET Framework 版本不同导致.同时也提供了两个解决方案:将. ...

  7. Python.错误解决:scrapy 没有crawl 命令

    确保2点: 1.把爬虫.py复制到spiders文件夹里 如执行scrapy crawl demo ,spiders里面就要有demo.py文件 2.在项目文件夹内执行命令 在scrapy.cfg所在 ...

  8. js,jq获取父,兄弟,子节点整理

    js获取节点 父: parentNode 获取已知节点的父节点. 子: childNodes; 得到全部子节点 children 得到全部子节点 firstChild 获得第一个子节点 lastChi ...

  9. Python中cPickle

    cPickle模块: 在python中,一般可以使用pickle类来进行python对象序列化,而cPickle提供了一个更快速简单的接口,如python文档所说:“cPickle - A faste ...

  10. 设置本地虚拟域名windows+apache

    C:\WINDOWS\system32\drivers\etc\hosts 在这个文件中 最下面添加. 127.0.0.1   localhost.com 127.0.0.1   cho.com 12 ...