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

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

IOS上实现的自定义仪表盘示例_第1张图片

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

// Gauge.h 
// GaugeDemo 
// 
// Created by 海锋 周 on 12-3-27. 
// Copyright (c) 2012年 CJLU rights reserved. 
// 
 
#import  
#import  
 
@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  
 
#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(ilabelNum*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(valmaxNum){ 
    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 
 

Demo的下载地址:http://xiazai.jb51.net/201701/yuanma/GaugeDemo_jb51.rar

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

你可能感兴趣的:(IOS上实现的自定义仪表盘示例)