IOS自定义仪表盘

时间:2023-09-02 17:43:44

周海锋 的专栏

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

2012-03-29 16:54 8583人阅读 评论(17) 收藏 举报
IOS自定义仪表盘 分类:
iPhone/iPad(33) IOS自定义仪表盘

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

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

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


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

IOS自定义仪表盘

 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