周海锋 的专栏

Objective-C/Cocos2d/Cocos2d-x/Php/JS

 
 
 
2012-03-29 16:54 8583人阅读 评论(17) 收藏 举报
 分类:
iPhone/iPad(33) 

版权声明:本文为博主原创文章,未经博主允许不得转载。

 【原创作品, 欢迎转载,转载请在明显处注明! 谢谢。

              原文地址:http://blog.csdn.net/toss156/article/details/7407770


今天给大家带来一个自定义的仪表盘,效果图如下。

 Demo中用到了 QuartzCore类 首先继承一个UIView。

  1. <span style="font-size:10px;">//
  2. //  Gauge.h
  3. //  GaugeDemo
  4. //
  5. //  Created by 海锋 周 on 12-3-27.
  6. //  Copyright (c) 2012年 CJLU rights reserved.
  7. //
  8. #import <UIKit/UIKit.h>
  9. #import <QuartzCore/QuartzCore.h>
  10. @interface Gauge : UIView
  11. {
  12. UIImage *gaugeView;
  13. UIImageView *pointer;
  14. CGFloat maxNum;
  15. CGFloat minNum;
  16. CGFloat maxAngle;
  17. CGFloat minAngle;
  18. CGFloat gaugeValue;
  19. CGFloat gaugeAngle;
  20. CGFloat angleperValue;
  21. CGFloat scoleNum;
  22. NSMutableArray *labelArray;
  23. CGContextRef context;
  24. }
  25. @property (nonatomic,retain) UIImage *gaugeView;
  26. @property (nonatomic,retain) UIImageView *pointer;
  27. @property (nonatomic,retain) NSMutableArray *labelArray;
  28. @property (nonatomic) CGContextRef context;
  29. -(void)setGaugeValue:(CGFloat)value animation:(BOOL)isAnim;
  30. @end</span><span style="font-size: 14px;">
  31. </span>


        指针的旋转是通过QuartzCore.framework中的CATransform3DRotate 来实现的,所以一定要记得把框架添加进来。当然在旋转之前,我们还需要把指针的中心pointer.layer.anchorPoint 移动到你需要的转动中心。

       在设置旋转动画的时候,我们用的不是CABaseAnimiation 而是用  CAKeyframeAnimation。这是因为如果使用中的 toValue 来实现旋转的话,它默认是以最小的旋转的,如果要实现控制旋转的方向的话,我们就只能用关键帧来设置旋转的路径。用关键帧的好处还有一个,就是可以给指针添加,旋转到指定位置以后的左右摆动的效果。

绘制仪表盘是通过Quartz2D来实现的,首先我们需要用UIGraphicsGetCurrentContext函数来获取一个Context上下文,就是相当于获取一个画布。然后就可以在上面通过三角函数的计算,画出背景图片,和上面的刻度线了。



  1. //
  2. //  Gauge.m
  3. //  GaugeDemo
  4. //
  5. //  Created by 海锋 周 on 12-3-27.
  6. //  Copyright (c) 2012年 CJLU. All rights reserved.
  7. //
  8. #import "Gauge.h"
  9. #import <QuartzCore/QuartzCore.h>
  10. #define MAXOFFSETANGLE 120.0f
  11. #define POINTEROFFSET  90.0f
  12. #define MAXVALUE       120.0f
  13. #define CELLMARKNUM    5
  14. #define CELLNUM        12
  15. #define GAUGESTRING    @"单位:Km/h"
  16. #define DEFLUATSIZE    300
  17. /************************************************
  18. 仪表盘的大小不建议设置的太小。
  19. 长宽都是300是最适合的
  20. 如果要更小的需要自行修改刻度长度和文字大小
  21. ---powered by 周海锋
  22. 2012-3-29
  23. ***********************************************/
  24. @implementation Gauge
  25. @interface Gauge (private)
  26. - (CGFloat) parseToX:(CGFloat) radius Angle:(CGFloat)angle;
  27. - (CGFloat) parseToY:(CGFloat) radius Angle:(CGFloat)angle;
  28. - (CGFloat) transToRadian:(CGFloat)angel;
  29. - (CGFloat) parseToAngle:(CGFloat) val;
  30. - (CGFloat) parseToValue:(CGFloat) val;
  31. - (void)setTextLabel:(NSInteger)labelNum;
  32. - (void)setLineMark:(NSInteger)labelNum;
  33. - (void) pointToAngle:(CGFloat) angle Duration:(CGFloat) duration;
  34. @end
  35. @synthesize gaugeView,pointer,context;
  36. @synthesize labelArray;
  37. - (id)initWithFrame:(CGRect)frame
  38. {
  39. self = [super initWithFrame:frame];
  40. if (self) {
  41. //设置背景透明
  42. [self setBackgroundColor:[UIColor clearColor]];
  43. scoleNum = DEFLUATSIZE/frame.size.width;
  44. maxNum = MAXVALUE;
  45. minNum = 0.0f;
  46. minAngle = -MAXOFFSETANGLE;
  47. maxAngle = MAXOFFSETANGLE;
  48. gaugeValue = 0.0f;
  49. gaugeAngle = -MAXOFFSETANGLE;
  50. angleperValue = (maxAngle - minAngle)/(maxNum - minNum);
  51. gaugeView= [UIImage imageNamed:@"gaugeback.png"];
  52. //添加指针
  53. UIImage *_pointer = [UIImage imageNamed:@"pointer2.png"];
  54. pointer = [[UIImageView alloc] initWithImage:_pointer];
  55. pointer.layer.anchorPoint = CGPointMake(0.5, 0.78);
  56. pointer.center = self.center;
  57. pointer.transform = CGAffineTransformMakeScale(scoleNum, scoleNum);
  58. [self addSubview:pointer];
  59. //设置文字标签
  60. [self setTextLabel:CELLNUM];
  61. //设置指针到0位置
  62. pointer.layer.transform = CATransform3DMakeRotation([self transToRadian:-MAXOFFSETANGLE], 0, 0, 1);
  63. }
  64. return self;
  65. }
  66. /*
  67. * setTextLabel 绘制刻度值
  68. * @labelNum NSInteger 刻度值的数目
  69. */
  70. -(void)setTextLabel:(NSInteger)labelNum
  71. {
  72. labelArray = [NSMutableArray arrayWithCapacity:labelNum];
  73. CGFloat textDis = (maxNum - minNum)/labelNum;
  74. CGFloat angelDis = (maxAngle - minAngle)/labelNum;
  75. CGFloat radius = (self.center.x - 75)*scoleNum;
  76. CGFloat currentAngle;
  77. CGFloat currentText = 0.0f;
  78. CGPoint centerPoint = self.center;
  79. for(int i=0;i<=labelNum;i++)
  80. {
  81. currentAngle = minAngle + i * angelDis - POINTEROFFSET;
  82. currentText = minNum + i * textDis;
  83. UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0 , 0 , 30, 50)];
  84. label.autoresizesSubviews = YES;
  85. label.textColor = [UIColor whiteColor];
  86. label.backgroundColor = [UIColor clearColor];
  87. //设置刻度的文字的格式
  88. if(i<labelNum/2){
  89. label.textAlignment = UITextAlignmentLeft;
  90. }else if (i==labelNum/2){
  91. label.textAlignment = UITextAlignmentCenter;
  92. }else{
  93. label.textAlignment = UITextAlignmentRight;
  94. }
  95. label.text = [NSString stringWithFormat:@"%d",(int)currentText];
  96. label.center = CGPointMake(centerPoint.x+[self parseToX:radius Angle:currentAngle],centerPoint.y+[self parseToY:radius Angle:currentAngle]);
  97. [labelArray addObject:label];
  98. [self addSubview:label];
  99. }
  100. // 设置刻度表的名称
  101. UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0 , 0 ,100, 40)];
  102. label.autoresizesSubviews = YES;
  103. label.textColor = [UIColor whiteColor];
  104. label.backgroundColor = [UIColor clearColor];
  105. label.textAlignment = UITextAlignmentCenter;
  106. label.text = GAUGESTRING;
  107. label.center = CGPointMake(centerPoint.x,centerPoint.y*3/2);
  108. [self addSubview:label];
  109. }
  110. /*
  111. * setLineMark 绘制刻度的标记
  112. * @labelNum NSInteger 刻度是数目
  113. */
  114. -(void)setLineMark:(NSInteger)labelNum
  115. {
  116. CGFloat angelDis = (maxAngle - minAngle)/labelNum;
  117. CGFloat radius = self.center.x;
  118. CGFloat currentAngle;
  119. CGPoint centerPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
  120. for(int i=0;i<=labelNum;i++)
  121. {
  122. currentAngle = minAngle + i * angelDis - POINTEROFFSET;
  123. //给刻度标记绘制不同的颜色
  124. if(i>labelNum*2/3)
  125. {
  126. CGContextSetStrokeColorWithColor(context, [[UIColor colorWithRed:1 green:0 blue:0 alpha:0.8] CGColor]);
  127. }else if(i>labelNum*1/3){
  128. CGContextSetStrokeColorWithColor(context, [[UIColor colorWithRed:1 green:1 blue:0 alpha:0.8] CGColor]);
  129. }else{
  130. CGContextSetStrokeColorWithColor(context, [[UIColor colorWithRed:0 green:1 blue:0 alpha:0.8] CGColor]);
  131. }
  132. //绘制不同的长短的刻度
  133. if(i%5==0)
  134. {
  135. CGContextSetLineCap(context, kCGLineCapSquare);
  136. CGContextSetLineWidth(context, 3);
  137. CGContextStrokePath(context);
  138. CGContextMoveToPoint(context,centerPoint.x+[self parseToX:radius-25*scoleNum Angle:currentAngle], centerPoint.y+[self parseToY:radius-25*scoleNum Angle:currentAngle]);
  139. CGContextAddLineToPoint(context,centerPoint.x+[self parseToX:radius-65*scoleNum Angle:currentAngle], centerPoint.y+[self parseToY:radius-65*scoleNum Angle:currentAngle]);
  140. }else{
  141. CGContextSetLineWidth(context, 2);
  142. CGContextSetLineCap(context, kCGLineCapSquare);
  143. CGContextStrokePath(context);
  144. CGContextMoveToPoint(context,centerPoint.x+[self parseToX:radius-25*scoleNum Angle:currentAngle], centerPoint.y+[self parseToY:radius-25*scoleNum Angle:currentAngle]);
  145. CGContextAddLineToPoint(context,centerPoint.x+[self parseToX:radius-40*scoleNum Angle:currentAngle], centerPoint.y+[self parseToY:radius-40*scoleNum Angle:currentAngle]);
  146. }
  147. }
  148. }
  149. /*
  150. * setGaugeValue 移动到某个数值
  151. * @value CGFloat 移动到的数值
  152. * @isAnim BOOL   是否执行动画
  153. */
  154. -(void)setGaugeValue:(CGFloat)value animation:(BOOL)isAnim
  155. {
  156. CGFloat tempAngle = [self parseToAngle:value];
  157. gaugeValue = value;
  158. //设置转动时间和转动动画
  159. if(isAnim){
  160. [self pointToAngle:tempAngle Duration:0.6f];
  161. }else
  162. {
  163. [self pointToAngle:tempAngle Duration:0.0f];
  164. }
  165. }
  166. /*
  167. * pointToAngle 按角度旋转
  168. * @angel CGFloat 角度
  169. * @duration CGFloat 动画执行时间
  170. */
  171. - (void) pointToAngle:(CGFloat) angle Duration:(CGFloat) duration
  172. {
  173. CAKeyframeAnimation *anim=[CAKeyframeAnimation animationWithKeyPath:@"transform"];
  174. NSMutableArray *values=[NSMutableArray array];
  175. anim.duration = duration;
  176. anim.autoreverses = NO;
  177. anim.fillMode = kCAFillModeForwards;
  178. anim.removedOnCompletion= NO;
  179. CGFloat distance = angle/10;
  180. //设置转动路径,不能直接用 CABaseAnimation 的toValue,那样是按最短路径的,转动超过180度时无法控制方向
  181. int i = 1;
  182. for(;i<=10;i++){
  183. [values addObject:[NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, [self transToRadian:(gaugeAngle+distance*i)], 0, 0, 1)]];
  184. }
  185. //添加缓动效果
  186. [values addObject:[NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, [self transToRadian:(gaugeAngle+distance*(i))], 0, 0, 1)]];
  187. [values addObject:[NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, [self transToRadian:(gaugeAngle+distance*(i-2))], 0, 0, 1)]];
  188. [values addObject:[NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, [self transToRadian:(gaugeAngle+distance*(i-1))], 0, 0, 1)]];
  189. anim.values=values; ;
  190. [pointer.layer addAnimation:anim forKey:@"cubeIn"];
  191. gaugeAngle = gaugeAngle+angle;
  192. }
  193. /*
  194. * parseToX 角度转弧度
  195. * @angel CGFloat 角度
  196. */
  197. -(CGFloat)transToRadian:(CGFloat)angel
  198. {
  199. return angel*M_PI/180;
  200. }
  201. /*
  202. * parseToX 根据角度,半径计算X坐标
  203. * @radius CGFloat 半径
  204. * @angle  CGFloat 角度
  205. */
  206. - (CGFloat) parseToX:(CGFloat) radius Angle:(CGFloat)angle
  207. {
  208. CGFloat tempRadian = [self transToRadian:angle];
  209. return radius*cos(tempRadian);
  210. }
  211. /*
  212. * parseToY 根据角度,半径计算Y坐标
  213. * @radius CGFloat 半径
  214. * @angle  CGFloat 角度
  215. */
  216. - (CGFloat) parseToY:(CGFloat) radius Angle:(CGFloat)angle
  217. {
  218. CGFloat tempRadian = [self transToRadian:angle];
  219. return radius*sin(tempRadian);
  220. }
  221. /*
  222. * parseToAngle 根据数据计算需要转动的角度
  223. * @val CGFloat 要移动到的数值
  224. */
  225. -(CGFloat) parseToAngle:(CGFloat) val
  226. {
  227. //异常的数据
  228. if(val<minNum){
  229. return minNum;
  230. }else if(val>maxNum){
  231. return maxNum;
  232. }
  233. CGFloat temp =(val-gaugeValue)*angleperValue;
  234. return temp;
  235. }
  236. /*
  237. * parseToValue 根据角度计算数值
  238. * @val CGFloat 要移动到的角度
  239. */
  240. -(CGFloat) parseToValue:(CGFloat) val
  241. {
  242. CGFloat temp=val/angleperValue;
  243. CGFloat temp2=maxNum/2+temp;
  244. if(temp2>maxNum){
  245. return maxNum;
  246. }else if(temp2<maxNum){
  247. return maxNum;
  248. }
  249. return temp2;
  250. }
  251. - (void)drawRect:(CGRect)rect
  252. {
  253. //获取上下文
  254. context = UIGraphicsGetCurrentContext();
  255. //设置背景透明
  256. CGContextSetFillColorWithColor(context,self.backgroundColor.CGColor);
  257. CGContextFillRect(context, rect);
  258. //绘制仪表背景
  259. [[self gaugeView ]drawInRect:self.bounds];
  260. //绘制刻度
  261. [self setLineMark:CELLNUM*CELLMARKNUM];
  262. CGContextStrokePath(context);
  263. }
  264. @end



Demo的下载地址:http://download.csdn.net/detail/toss156/4183721

IOS自定义仪表盘的更多相关文章

  1. 【iOS自定义键盘及键盘切换】详解

    [iOS自定义键盘]详解 实现效果展示: 一.实现的协议方法代码 #import <UIKit/UIKit.h> //创建自定义键盘协议 @protocol XFG_KeyBoardDel ...

  2. iOS自定义的UISwitch按钮

    UISwitch开关控件 开关代替了点选框.开关是到目前为止用起来最简单的控件,不过仍然可以作一定程度的定制化. 一.创建 UISwitch* mySwitch = [[ UISwitchalloc] ...

  3. 如何实现 iOS 自定义状态栏

    给大家介绍如何实现 iOS 自定义状态栏 Sample Code: 01 UIWindow * statusWindow = [[UIWindow alloc] initWithFrame:[UIAp ...

  4. iOS自定义组与组之间的距离以及视图

    iOS自定义组与组之间的距离以及视图 //头视图高度 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(N ...

  5. iOS 自定义转场动画

    代码地址如下:http://www.demodashi.com/demo/12955.html 一.总效果 本文记录分享下自定义转场动画的实现方法,具体到动画效果:新浪微博图集浏览转场效果.手势过渡动 ...

  6. iOS 自定义转场动画浅谈

    代码地址如下:http://www.demodashi.com/demo/11612.html 路漫漫其修远兮,吾将上下而求索 前记 想研究自定义转场动画很久了,时间就像海绵,挤一挤还是有的,花了差不 ...

  7. iOS自定义转场动画实战讲解

    iOS自定义转场动画实战讲解   转场动画这事,说简单也简单,可以通过presentViewController:animated:completion:和dismissViewControllerA ...

  8. IOS自定义表格UITableViewCell

    在UITableView中,自定义表格,最原始是继承UITableViewCell,然后通过写代码方式去搞,但是这个费事了. 1.在storyboard中 给一个ViewController的tabi ...

  9. ios 自定义键盘

    由于项目需要,需要自定义键盘.ios系统键盘会缓存键盘输入,并保存在系统目录下的文件里,并且是明文存储,存在帐号密码泄漏风险.在别人代码基础上修改了下,美化了下界面,去掉了字符输入,加了点击特效,截图 ...

随机推荐

  1. Java基础(46):选择排序的Java封装(完整可运行)

    1 package lsg.ap.select; import java.util.Random; public class SelectSort { //选择排序 /** *@author: 梁山广 ...

  2. .NET: 配置文件

    VS里项目->添加新项->应用程序配置文件 <?xml version="1.0" encoding="utf-8" ?> <co ...

  3. struts一些实用常量配置_2015.01.04

  4. 17---Net基础加强

    更新中,敬请期待............ 复习 将xml显示到treeview 修改增加 删除 foreach原理 深拷贝与浅拷贝 模拟数据库及登陆 复习总结

  5. Android应用开发中的风格和主题(style,themes)

    http://www.cnblogs.com/playing/archive/2011/04/01/2002469.html 越来越多互联网企业都在Android平台上部署其客户端,为了提升用户体验, ...

  6. 用jQuery创建HTML中不存在的标签元素碰到的问题

    如果你自定义了一个标签,比如<aaa></aaa> 用jQuery的写法,比如var custom_element = $('<aaa class="ee&qu ...

  7. 【NOIP模拟赛】正方形大阵

    正方形大阵 [问题描述]   [输入格式]   第一行一个正整数n代表询问次数. 接下来n行每行一个不超过八位的小数k代表一组询问. [输出格式]   输出共n行,代表每次询问的答案:如果有无数个交点 ...

  8. selenium webdriver设置超时

    webdriver类中有三个和时间相关的方法: 1.pageLoadTimeout 2.setScriptTimeout 3.implicitlyWait pageLoadTimeout from s ...

  9. !important------至高无上的宝剑

    如上图,不同来源的两个样式,第一个样式设置了font-weight,第二个没有,浏览器会把它叠加在一起,即浏览器会把各个零散的整合成一个整体.第一个样式color:red,第二个样式color:blu ...

  10. 用grunt搭建自动化的web前端开发环境实战教程(详细步骤)

    用grunt搭建自动化的web前端开发环境实战教程(详细步骤) jQuery在使用grunt,bootstrap在使用grunt,百度UEditor在使用grunt,你没有理由不学.不用!前端自动化, ...