Android 自定义UI--指南针

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

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

[html] view plaincopy

  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个刻度之后调用这个方法。

时间: 2024-10-19 21:41:23

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

android自定义UI模板图文详解

不知道大家在实际开发中有没有自定义过UI模板?今天花时间研究了一下android中自定义UI模板,与大家分享一下. 每个设计良好的App都是自定义标题栏,在自定义标题栏的过程中大部分人可能都是自定义一个标题的xml文件,然后在需要的地方直接通过include来引用,这比起在每个布局文件中写标题栏已经进化很多了,但仍然不是最简单有效的方法,我们为什么不能自定义一个标题控件呢?今天就带大家自己做一个标题栏控件.效果图如下: 开始啦: 第一步:自定义xml属性 新建一个android项目,在value

Android 自定义UI圆角按钮

Android实际开发中我们一般需要圆角的按钮,一般情况下我们可以让美工做出来相应的按钮图片,然后放上去即可,另外我们可以在布局文件中直接设置,也可以达到一样的效果.下面讲解在布局文件中自定义圆角按钮的小Demo. 代码很简单,实现效果图: 源代码: 源代码: 这里主要是xml布局文件实现: MainActivity: package com.android_drawableresource; import android.app.Activity; import android.os.Bund

Android自定义UI陷阱:LayoutInflater.from().inflate()一定不能工作在父类或虚类里

问题背景:有一些UI具有共性,比如常见的app第一次运行时出现的各种指示框,告诉你往哪搓是调音量的,往哪点是调屏幕亮度的,当点击这些VIew,则其自动消失.或者一动时间后,自动消失.另外一个问题是,不同的方向下加载出来的指示View内容是不一样的. 为此需要将这些特点的View抽象出来,写个父类或者说是基类,为啥一定要这样搞,这样写好处很多.优点如下: 1.可以让代码变得更简洁.每个子View里的共同的方法都由父类来做,每个子View实现自己的逻辑就ok了. 2.因为这些View只工作一次,所以

Android自定义UI控件(简单方便版,但不灵活)

这种方法的优点就是简单,容易理解,适合开发一些不经常用到的自定义UI控件 缺点就是比较不灵活,如果其他应用想使用这个控件的话得改很多 简单来说,这个方法是用来做成品的,下一篇的方法是用来做模板的. 先看成品,这是一个标题栏控件: 由左右两个按钮和中一个TextView组成: 实现方法: 第一步:定义一个xml文件,用来设计你自定义控件的雏形 示例代码:文件名为title 1 <?xml version="1.0" encoding="utf-8"?> 2

Android自定义UI的实现和应用

在Android项目开发中,不可避免的要遇到自定义的UI,用较好的体验去讨好UED妹子和交互设计师手下留情~几个迭代下来,遇到了不少这样的要求,有简单有复杂.最好的实现方案就是讲业务和UI隔离,封装成独立的UI控件供以后复用.以下列举几个项目中用到的例子,源代码有的已经整理到Github,还有一些需要优化后再整理到GIthub上,暂时先把例子展示出来,待续... 目前的项目:嗨健康.各大应用市场免费哦,欢迎下载体验... O.柱状图动态绘制 这个是为了展示计步历史记录的,分周和月两个展示维度,均

Android自定义UI模板

第一步:自定义xml属性 新建一个android项目,在values文件夹中新建一个atts.xml的文件,在这个xml文件中声明我们一会在使用自定义控件时候需要指明的属性.atts.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 4 <declare-styleable name="ToolBar"> 5 <attr name=&

android自定义View之NotePad出鞘记

现在我们的手机上基本都会有一个记事本,用起来倒也还算方便,记事本这种东东,如果我想要自己实现,该怎么做呢?今天我们就通过自定义View的方式来自定义一个记事本.OK,废话不多说,先来看看效果图. 整个页面还是很简单的. 1.自定义View的分类 OK,那么在正文开始之前,我想先来说说自定义View的分类,自定义View我们一共分为三类 1.自绘控件 自绘控件就是我们自定义View继承自已有控件,然后扩展其功能,之前两篇自定义View的博客(android自定义View之钟表诞生记,android

Android UI开源组件库BottomView ,第三方自定义UI控件

这里分享一个Android的非常经典实用而且简单方便的第三方UI控件库:BottomView(小米的米UI也用到了这个) 实现功能: 可以在底部弹出的View里自定义布局: 可以自定义是否可以触摸外部消失: 可以自定义事件: 可以自定义外围背景是否透明: 可以自定义动画: 如果需要的话,可以强制为顶部View显示 BottomView.jar库文件下载地址:http://download.csdn.net/detail/jay100500/7547055 BottomView的Demo下载地址:

Android开发之自定义UI组件和属性

Android系统虽然自带了很多的组件,但肯定满足我们个性化的需求,所以我们为了开发方便,需要自定义Android的UI组件,以实现我们个性化的需求. 自定义组合控件的步骤: 1 .自定一个View,需要继承相对布局,线性布局等ViewGroup的子类.ViewGroup是一个其他控件的容器,能够乘放各种组件. 2 .实现父类的3个构造方法.一般需要在构造方法里始化初自定义布局文件. 一个参数构造方法:为new控件使用 两个参数的造方法:在调用布局文件使用 两个参数的造方法:传递带有样式的布局文

Android自定义TabActivity(实现仿新浪微博底部菜单更新UI)

如今Android上很多应用都采用底部菜单控制更新的UI这种框架,例如新浪微博 点击底部菜单的选项可以更新界面.底部菜单可以使用TabHost来实现,不过用过TabHost的人都知道自定义TabHost究竟是有多麻烦的,原生TabHost的风格是不依附屏幕的底部的,要依附底部就要重写布局. TabHost设置的Container可以管理UI的显示,UI可以用LayoutInflater动态生成,也可以是Activity,但不好管理Activity的生命周期.然后用TabHost控制显示UI的显示