有了之前的基础,下面开始实现一个简单的指南针。首先来看一下效果图,

我们可以粗略将这个指南针分为三个部分,一是圆形背景,二是刻度,三是文本。那么在写代码的时候,就可以声明三个Paint画笔来画以上三个物体。代码如下:

  1. package com.example.apptest;
  2. import android.content.Context;
  3. import android.graphics.Canvas;
  4. import android.graphics.Color;
  5. import android.graphics.Paint;
  6. import android.util.AttributeSet;
  7. import android.util.Log;
  8. import android.view.View;
  9. /**
  10. * 指南针
  11. *
  12. */
  13. class CompassView extends View {
  14. //刻度画笔
  15. private Paint markerPaint;
  16. //文本画笔
  17. private Paint textPaint;
  18. //圆形画笔
  19. private Paint circlePaint;
  20. //字符串
  21. private String northString;
  22. //字符串
  23. private String eastString;
  24. //字符串
  25. private String southString;
  26. //字符串
  27. private String westString;
  28. //文本高度
  29. private int textHeight;
  30. //轴
  31. private float bearing;
  32. /**
  33. *
  34. * @param _bearing
  35. */
  36. public void setBearing(float _bearing) {
  37. bearing = _bearing;
  38. }
  39. /**
  40. *
  41. * @return
  42. */
  43. public float getBearing() {
  44. return bearing;
  45. }
  46. public CompassView(Context context) {
  47. super(context);
  48. initCompassView();
  49. }
  50. public CompassView(Context context, AttributeSet attrs) {
  51. super(context, attrs);
  52. initCompassView();
  53. }
  54. public CompassView(Context context, AttributeSet attrs, int defaultStyle) {
  55. super(context, attrs, defaultStyle);
  56. initCompassView();
  57. }
  58. protected void initCompassView() {
  59. setFocusable(true);
  60. // 东西南北
  61. northString = "北";
  62. eastString = "东";
  63. southString = "南";
  64. westString = "西";
  65. // 设置实心圆画笔
  66. circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  67. circlePaint.setColor(Color.BLACK);
  68. circlePaint.setStrokeWidth(1);
  69. circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
  70. // 设置线条画笔 刻度
  71. markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  72. markerPaint.setColor(Color.RED);
  73. // 设置坐标画笔 东西南北 度数
  74. textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  75. textPaint.setColor(Color.WHITE);
  76. // 设置文字高度
  77. textHeight = (int) textPaint.measureText("yY");
  78. Log.i("textHeight", textHeight+"");
  79. }
  80. @Override
  81. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  82. int measuredWidth = measure(widthMeasureSpec);
  83. int measuredHeight = measure(heightMeasureSpec);
  84. int d = Math.min(measuredWidth, measuredHeight);
  85. setMeasuredDimension(d, d);
  86. }
  87. /**
  88. * @category
  89. * @param measureSpec
  90. * @return
  91. */
  92. private int measure(int measureSpec) {
  93. int result = 0;
  94. int specMode = MeasureSpec.getMode(measureSpec);
  95. int specSize = MeasureSpec.getSize(measureSpec);
  96. if (specMode == MeasureSpec.UNSPECIFIED) {
  97. result = 200;
  98. } else {
  99. result = specSize;
  100. }
  101. return result;
  102. }
  103. @Override
  104. protected void onDraw(Canvas canvas) {
  105. // 圆心坐标
  106. int px = getMeasuredWidth() / 2;
  107. Log.i("px", px+"");
  108. int py = getMeasuredHeight() / 2;
  109. Log.i("py", py+"");
  110. // 半径 取最小值
  111. int radius = Math.min(px, py);
  112. Log.i("radius", radius+"");
  113. // 画圆
  114. canvas.drawCircle(px, py, radius, circlePaint);
  115. canvas.save();
  116. canvas.rotate(-bearing, px, py);
  117. // 东西南北 坐标位置
  118. int textWidth = (int) textPaint.measureText("W");
  119. Log.i("textWidth", textWidth+"");
  120. int cardinalX = px - textWidth / 2;
  121. Log.i("cardinalX", cardinalX+"");
  122. int cardinalY = py - radius + textHeight;
  123. Log.i("cardinalY", cardinalY+"");
  124. //画24个刻度
  125. for (int i = 0; i < 24; i++) {
  126. //画刻度
  127. canvas.drawLine(px, py - radius, px, py - radius + 10, markerPaint);
  128. canvas.save();
  129. //移动原点textHeight距离 开始画东西南北以及度数
  130. canvas.translate(0, textHeight);
  131. //判断如果满足条件画东西南北
  132. if (i % 6 == 0) {
  133. String dirString = "";
  134. switch (i) {
  135. case (0): {
  136. dirString = northString;
  137. // 画指南针
  138. int arrowY = 2 * textHeight;
  139. canvas.drawLine(px, arrowY, px - 5, 3 * textHeight,
  140. markerPaint);
  141. canvas.drawLine(px, arrowY, px + 5, 3 * textHeight,
  142. markerPaint);
  143. break;
  144. }
  145. case (6):
  146. dirString = eastString;
  147. break;
  148. case (12):
  149. dirString = southString;
  150. break;
  151. case (18):
  152. dirString = westString;
  153. break;
  154. }
  155. //画东西南北
  156. canvas.drawText(dirString, cardinalX, cardinalY, textPaint);
  157. }else if (i % 3 == 0) {//判断如果满足条件画4个度数
  158. String angle = String.valueOf(i * 15);
  159. float angleTextWidth = textPaint.measureText(angle);
  160. int angleTextX = (int) (px - angleTextWidth / 2);
  161. int angleTextY = py - radius + textHeight;
  162. //画弧度数
  163. canvas.drawText(angle, angleTextX, angleTextY, textPaint);
  164. }
  165. canvas.restore();
  166. //每隔15度旋转一下
  167. canvas.rotate(15, px, py);
  168. }
  169. canvas.restore();
  170. }
  171. }

这个例子中,多了一个measure过程,重写了OnMeasure()过程,用于计算View的大小。先不细说这个,下面重点说一下如何画图的。背景很简单,不多说,难点还是在于刻度以及文字的实现。我们知道,画文本可以使用drawText()方法,画刻度也就是画直线,可以使用drawLine()方法。那关键问题就是在哪个位置画刻度以及文本。本例子中,圆形的大小取决于屏幕的宽度,可以看到圆形的直接就是屏幕的宽度。画刻度线也是从圆心坐标开始的,直接使用drawLine()方法。还有一个地方需要注意就是东西南北以及刻度的文字是移动了一段距离后开始绘制的,使用的方法就是translate(),在画完14个刻度之后调用这个方法。

Android 自定义UI--指南针的更多相关文章

  1. android自定义UI模板图文详解

    不知道大家在实际开发中有没有自定义过UI模板?今天花时间研究了一下android中自定义UI模板,与大家分享一下. 每个设计良好的App都是自定义标题栏,在自定义标题栏的过程中大部分人可能都是自定义一 ...

  2. Android自定义UI的实现和应用

    在Android项目开发中,不可避免的要遇到自定义的UI,用较好的体验去讨好UED妹子和交互设计师手下留情~几个迭代下来,遇到了不少这样的要求,有简单有复杂.最好的实现方案就是讲业务和UI隔离,封装成 ...

  3. Android自定义UI模板

    第一步:自定义xml属性 新建一个android项目,在values文件夹中新建一个atts.xml的文件,在这个xml文件中声明我们一会在使用自定义控件时候需要指明的属性.atts.xml < ...

  4. android自定义View之NotePad出鞘记

    现在我们的手机上基本都会有一个记事本,用起来倒也还算方便,记事本这种东东,如果我想要自己实现,该怎么做呢?今天我们就通过自定义View的方式来自定义一个记事本.OK,废话不多说,先来看看效果图. 整个 ...

  5. Android开源的精美日历控件,热插拔设计的万能自定义UI

    Android开源的精美日历控件,热插拔设计的万能自定义UI UI框架应该逻辑与界面实现分离,该日历控件使用了热插拔的设计 ,简单几步即可实现你需要的UI效果,热插拔的思想是你提供你的实现,我提供我的 ...

  6. Android自定义View和控件之一-定制属于自己的UI

    照例,拿来主义.我的学习是基于下面的三篇blog.前两是基本的流程,第三篇里有比较细致的绘制相关的属性.第4篇介绍了如何减少布局层次来提高效率. 1. 教你搞定Android自定义View 2. 教你 ...

  7. Android自定义View 画弧形,文字,并增加动画效果

    一个简单的Android自定义View的demo,画弧形,文字,开启一个多线程更新ui界面,在子线程更新ui是不允许的,但是View提供了方法,让我们来了解下吧. 1.封装一个抽象的View类   B ...

  8. Android 自定义View合集

    自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...

  9. Android 自定义View (五)——实践

    前言: 前面已经介绍了<Android 自定义 view(四)-- onMeasure 方法理解>,那么这次我们就来小实践下吧 任务: 公司现有两个任务需要我完成 (1)监测液化天然气液压 ...

  10. [原] Android 自定义View步骤

    例子如下:Android 自定义View 密码框 例子 1 良好的自定义View 易用,标准,开放. 一个设计良好的自定义view和其他设计良好的类很像.封装了某个具有易用性接口的功能组合,这些功能能 ...

随机推荐

  1. c - 字符串长度.

    //字符串的长度. int lenOfStr(char *s) { char *p = s; ; while(*p++) len++; return len; }

  2. string.Format 指定字符串宽度

    语法: { index[,alignment][:formatString]} index,为索引号,不用多说. alignment,是一个带符号的整数,绝对值的大小表示字段的宽度. formatSt ...

  3. DataBase First创建数据库

    Entity Framework:ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapping) 解决方案,并提供了三种模式,分 ...

  4. Sql Server添加用户

    1.sa用户登陆之后,在安全性中新建登录名 2.添加登录名,下面的默认数据库选择该用户可访问的默认数据库 3.服务器角色中选择public 4.用户映射中选择该用户可访问的数据库,数据库角色一般选择p ...

  5. javascript 操作 css Rule

    //add addCssRule('.bcd',{'color':'red','font-weight':'bold','font-size':'12px'},document.styleSheets ...

  6. 武汉科技大学ACM :1005: 零起点学算法101——手机短号

    Problem Description 大家都知道,手机号是一个11位长的数字串,同时,作为学生,还可以申请加入校园网,如果加入成功,你将另外拥有一个短号.假设所有的短号都是是 6+手机号的后5位,比 ...

  7. POJ3641 Pseudoprime numbers(快速幂+素数判断)

    POJ3641 Pseudoprime numbers p是Pseudoprime numbers的条件: p是合数,(p^a)%p=a;所以首先要进行素数判断,再快速幂. 此题是大白P122 Car ...

  8. 网狐6603 cocos2dx 棋牌、捕鱼、休闲类游戏《李逵捕鱼》手机端完整源码分析及分享

    该资源说明: cocos2d 棋牌.捕鱼.休闲类游戏<李逵捕鱼>手机端完整源码,网狐6603配套手机版源码,可以选桌子,适合新手学习参考,小编已亲测试,绝对完整可编译手机端,下载后将文件考 ...

  9. Vim的snipMate插件

    介绍终于发现了一个插件,对于Vim下代码块的自动补全支持的很好.给大家推荐snipMate. snipMate可以帮助您在vim上实现类似Textmate的功能,自动代码块的能力非常强大,而且代码块是 ...

  10. C++得到最大的int值

    要得到最大的int值: 1.利用(unsigned int)-1,这样得到的就是unsigned int表示的最大值. 2.int值只是比unsigned int多一位符号位,所以对(unsigned ...