IOS自定义仪表盘

 
 

[置顶] 【IOS】IOS上实现的自定义仪表盘(可以用在流量监控之类的应用上)

标签: iosdistanceanimationuiviewinterfacequartz
 分类:

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

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


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

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

[cpp] view plain copy
 
  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.   
  9. #import <UIKit/UIKit.h>  
  10. #import <QuartzCore/QuartzCore.h>  
  11.   
  12. @interface Gauge : UIView  
  13. {  
  14.     UIImage *gaugeView;  
  15.     UIImageView *pointer;  
  16.       
  17.     CGFloat maxNum;  
  18.     CGFloat minNum;  
  19.       
  20.     CGFloat maxAngle;  
  21.     CGFloat minAngle;  
  22.       
  23.     CGFloat gaugeValue;  
  24.     CGFloat gaugeAngle;  
  25.       
  26.     CGFloat angleperValue;  
  27.     CGFloat scoleNum;  
  28.       
  29.     NSMutableArray *labelArray;  
  30.     CGContextRef context;  
  31. }  
  32.   
  33. @property (nonatomic,retain) UIImage *gaugeView;  
  34. @property (nonatomic,retain) UIImageView *pointer;  
  35. @property (nonatomic,retain) NSMutableArray *labelArray;  
  36. @property (nonatomic) CGContextRef context;  
  37. -(void)setGaugeValue:(CGFloat)value animation:(BOOL)isAnim;  
  38.   
  39. @end</span><span style="font-size: 14px;">  
  40. </span>  
        指针的旋转是通过QuartzCore.framework中的CATransform3DRotate 来实现的,所以一定要记得把框架添加进来。当然在旋转之前,我们还需要把指针的中心pointer.layer.anchorPoint 移动到你需要的转动中心。

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

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


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

Demo的下载地址:http://download.csdn.net/detail/toss156/4183721
原文地址:https://www.cnblogs.com/wcLT/p/5163341.html