首页 > 系统 > iOS > 正文

IOS上实现的自定义仪表盘示例

2020-07-26 02:57:44
字体:
来源:转载
供稿:网友

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

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

// Gauge.h // GaugeDemo // // Created by 海锋 周 on 12-3-27. // Copyright (c) 2012年 CJLU rights reserved. //  #import <UIKit/UIKit.h> #import <QuartzCore/QuartzCore.h>  @interface Gauge : UIView {   UIImage *gaugeView;   UIImageView *pointer;      CGFloat maxNum;   CGFloat minNum;      CGFloat maxAngle;   CGFloat minAngle;      CGFloat gaugeValue;   CGFloat gaugeAngle;      CGFloat angleperValue;   CGFloat scoleNum;      NSMutableArray *labelArray;   CGContextRef context; }  @property (nonatomic,retain) UIImage *gaugeView; @property (nonatomic,retain) UIImageView *pointer; @property (nonatomic,retain) NSMutableArray *labelArray; @property (nonatomic) CGContextRef context; -(void)setGaugeValue:(CGFloat)value animation:(BOOL)isAnim;  @end

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

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

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

// Gauge.m // GaugeDemo // // Created by 海锋 周 on 12-3-27. // Copyright (c) 2012年 CJLU. All rights reserved. //  #import "Gauge.h" #import <QuartzCore/QuartzCore.h>  #define MAXOFFSETANGLE 120.0f #define POINTEROFFSET 90.0f #define MAXVALUE    120.0f #define CELLMARKNUM  5 #define CELLNUM    12 #define GAUGESTRING  @"单位:Km/h" #define DEFLUATSIZE  300     /************************************************   仪表盘的大小不建议设置的太小。   长宽都是300是最适合的   如果要更小的需要自行修改刻度长度和文字大小               ---powered by 周海锋                 2012-3-29  ***********************************************/   @implementation Gauge  @interface Gauge (private) - (CGFloat) parseToX:(CGFloat) radius Angle:(CGFloat)angle; - (CGFloat) parseToY:(CGFloat) radius Angle:(CGFloat)angle; - (CGFloat) transToRadian:(CGFloat)angel; - (CGFloat) parseToAngle:(CGFloat) val; - (CGFloat) parseToValue:(CGFloat) val; - (void)setTextLabel:(NSInteger)labelNum; - (void)setLineMark:(NSInteger)labelNum; - (void) pointToAngle:(CGFloat) angle Duration:(CGFloat) duration; @end  @synthesize gaugeView,pointer,context; @synthesize labelArray;  - (id)initWithFrame:(CGRect)frame {   self = [super initWithFrame:frame];   if (self) {     //设置背景透明     [self setBackgroundColor:[UIColor clearColor]];          scoleNum = DEFLUATSIZE/frame.size.width;     maxNum = MAXVALUE;     minNum = 0.0f;     minAngle = -MAXOFFSETANGLE;     maxAngle = MAXOFFSETANGLE;     gaugeValue = 0.0f;     gaugeAngle = -MAXOFFSETANGLE;     angleperValue = (maxAngle - minAngle)/(maxNum - minNum);          gaugeView= [UIImage imageNamed:@"gaugeback.png"];     //添加指针     UIImage *_pointer = [UIImage imageNamed:@"pointer2.png"];     pointer = [[UIImageView alloc] initWithImage:_pointer];     pointer.layer.anchorPoint = CGPointMake(0.5, 0.78);     pointer.center = self.center;     pointer.transform = CGAffineTransformMakeScale(scoleNum, scoleNum);     [self addSubview:pointer];     //设置文字标签     [self setTextLabel:CELLNUM];     //设置指针到0位置     pointer.layer.transform = CATransform3DMakeRotation([self transToRadian:-MAXOFFSETANGLE], 0, 0, 1);   }   return self; }  /*  * setTextLabel 绘制刻度值  * @labelNum NSInteger 刻度值的数目  */ -(void)setTextLabel:(NSInteger)labelNum {    labelArray = [NSMutableArray arrayWithCapacity:labelNum];      CGFloat textDis = (maxNum - minNum)/labelNum;   CGFloat angelDis = (maxAngle - minAngle)/labelNum;   CGFloat radius = (self.center.x - 75)*scoleNum;   CGFloat currentAngle;   CGFloat currentText = 0.0f;   CGPoint centerPoint = self.center;      for(int i=0;i<=labelNum;i++)   {     currentAngle = minAngle + i * angelDis - POINTEROFFSET;     currentText = minNum + i * textDis;     UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0 , 0 , 30, 50)];     label.autoresizesSubviews = YES;     label.textColor = [UIColor whiteColor];     label.backgroundColor = [UIColor clearColor];     //设置刻度的文字的格式     if(i<labelNum/2){       label.textAlignment = UITextAlignmentLeft;     }else if (i==labelNum/2){       label.textAlignment = UITextAlignmentCenter;     }else{       label.textAlignment = UITextAlignmentRight;     }     label.text = [NSString stringWithFormat:@"%d",(int)currentText];     label.center = CGPointMake(centerPoint.x+[self parseToX:radius Angle:currentAngle],centerPoint.y+[self parseToY:radius Angle:currentAngle]);          [labelArray addObject:label];     [self addSubview:label];       }   // 设置刻度表的名称   UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0 , 0 ,100, 40)];   label.autoresizesSubviews = YES;   label.textColor = [UIColor whiteColor];   label.backgroundColor = [UIColor clearColor];   label.textAlignment = UITextAlignmentCenter;   label.text = GAUGESTRING;   label.center = CGPointMake(centerPoint.x,centerPoint.y*3/2);   [self addSubview:label];   }  /*  * setLineMark 绘制刻度的标记  * @labelNum NSInteger 刻度是数目  */ -(void)setLineMark:(NSInteger)labelNum {    CGFloat angelDis = (maxAngle - minAngle)/labelNum;   CGFloat radius = self.center.x;   CGFloat currentAngle;   CGPoint centerPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);      for(int i=0;i<=labelNum;i++)   {     currentAngle = minAngle + i * angelDis - POINTEROFFSET;     //给刻度标记绘制不同的颜色     if(i>labelNum*2/3)     {       CGContextSetStrokeColorWithColor(context, [[UIColor colorWithRed:1 green:0 blue:0 alpha:0.8] CGColor]);     }else if(i>labelNum*1/3){       CGContextSetStrokeColorWithColor(context, [[UIColor colorWithRed:1 green:1 blue:0 alpha:0.8] CGColor]);     }else{       CGContextSetStrokeColorWithColor(context, [[UIColor colorWithRed:0 green:1 blue:0 alpha:0.8] CGColor]);     }     //绘制不同的长短的刻度     if(i%5==0)     {          CGContextSetLineCap(context, kCGLineCapSquare);       CGContextSetLineWidth(context, 3);       CGContextStrokePath(context);         CGContextMoveToPoint(context,centerPoint.x+[self parseToX:radius-25*scoleNum Angle:currentAngle], centerPoint.y+[self parseToY:radius-25*scoleNum Angle:currentAngle]);       CGContextAddLineToPoint(context,centerPoint.x+[self parseToX:radius-65*scoleNum Angle:currentAngle], centerPoint.y+[self parseToY:radius-65*scoleNum Angle:currentAngle]);     }else{       CGContextSetLineWidth(context, 2);       CGContextSetLineCap(context, kCGLineCapSquare);       CGContextStrokePath(context);        CGContextMoveToPoint(context,centerPoint.x+[self parseToX:radius-25*scoleNum Angle:currentAngle], centerPoint.y+[self parseToY:radius-25*scoleNum Angle:currentAngle]);       CGContextAddLineToPoint(context,centerPoint.x+[self parseToX:radius-40*scoleNum Angle:currentAngle], centerPoint.y+[self parseToY:radius-40*scoleNum Angle:currentAngle]);       }   } }  /*  * setGaugeValue 移动到某个数值  * @value CGFloat 移动到的数值  * @isAnim BOOL  是否执行动画  */ -(void)setGaugeValue:(CGFloat)value animation:(BOOL)isAnim {   CGFloat tempAngle = [self parseToAngle:value];   gaugeValue = value;   //设置转动时间和转动动画   if(isAnim){     [self pointToAngle:tempAngle Duration:0.6f];   }else   {     [self pointToAngle:tempAngle Duration:0.0f];   } }  /*  * pointToAngle 按角度旋转  * @angel CGFloat 角度  * @duration CGFloat 动画执行时间  */ - (void) pointToAngle:(CGFloat) angle Duration:(CGFloat) duration {   CAKeyframeAnimation *anim=[CAKeyframeAnimation animationWithKeyPath:@"transform"];    NSMutableArray *values=[NSMutableArray array];    anim.duration = duration;   anim.autoreverses = NO;   anim.fillMode = kCAFillModeForwards;   anim.removedOnCompletion= NO;      CGFloat distance = angle/10;   //设置转动路径,不能直接用 CABaseAnimation 的toValue,那样是按最短路径的,转动超过180度时无法控制方向   int i = 1;   for(;i<=10;i++){     [values addObject:[NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, [self transToRadian:(gaugeAngle+distance*i)], 0, 0, 1)]];     }   //添加缓动效果    [values addObject:[NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, [self transToRadian:(gaugeAngle+distance*(i))], 0, 0, 1)]];    [values addObject:[NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, [self transToRadian:(gaugeAngle+distance*(i-2))], 0, 0, 1)]];       [values addObject:[NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, [self transToRadian:(gaugeAngle+distance*(i-1))], 0, 0, 1)]];                                          anim.values=values; ;   [pointer.layer addAnimation:anim forKey:@"cubeIn"];      gaugeAngle = gaugeAngle+angle;    }  /*  * parseToX 角度转弧度  * @angel CGFloat 角度  */ -(CGFloat)transToRadian:(CGFloat)angel {   return angel*M_PI/180; }   /*  * parseToX 根据角度,半径计算X坐标  * @radius CGFloat 半径   * @angle CGFloat 角度  */ - (CGFloat) parseToX:(CGFloat) radius Angle:(CGFloat)angle {   CGFloat tempRadian = [self transToRadian:angle];   return radius*cos(tempRadian); }  /*  * parseToY 根据角度,半径计算Y坐标  * @radius CGFloat 半径   * @angle CGFloat 角度  */ - (CGFloat) parseToY:(CGFloat) radius Angle:(CGFloat)angle {   CGFloat tempRadian = [self transToRadian:angle];   return radius*sin(tempRadian); }  /*  * parseToAngle 根据数据计算需要转动的角度  * @val CGFloat 要移动到的数值  */ -(CGFloat) parseToAngle:(CGFloat) val {   //异常的数据   if(val<minNum){     return minNum;   }else if(val>maxNum){     return maxNum;   }   CGFloat temp =(val-gaugeValue)*angleperValue;   return temp; }  /*  * parseToValue 根据角度计算数值  * @val CGFloat 要移动到的角度  */ -(CGFloat) parseToValue:(CGFloat) val {   CGFloat temp=val/angleperValue;   CGFloat temp2=maxNum/2+temp;   if(temp2>maxNum){     return maxNum;   }else if(temp2<maxNum){     return maxNum;   }   return temp2; }  - (void)drawRect:(CGRect)rect  {   //获取上下文   context = UIGraphicsGetCurrentContext();   //设置背景透明   CGContextSetFillColorWithColor(context,self.backgroundColor.CGColor);   CGContextFillRect(context, rect);   //绘制仪表背景     [[self gaugeView ]drawInRect:self.bounds];   //绘制刻度   [self setLineMark:CELLNUM*CELLMARKNUM];        CGContextStrokePath(context); }  @end 

Demo的下载地址:http://xiazai.VeVB.COm/201701/yuanma/GaugeDemo_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表