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

所属分类: 软件编程 / IOS 阅读数: 1315
收藏 0 赞 0 分享

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

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.jb51.net/201701/yuanma/GaugeDemo_jb51.rar

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

更多精彩内容其他人还在看

IOS开发相册图片多选和删除的功能

之前小编有和大家分享过一篇关于从相册选取单张照片的文章,那么下面这篇文章跟大家分享下如何相册多图选择和删除,以及包括拍照功能,有需要的可以参考学习,下面来一起看看吧。
收藏 0 赞 0 分享

iOS使用runtime修改文本框(TextField)的占位文字颜色

相信大家都知道TextField默认的占位颜色也是深灰色,这个颜色比较难看清,这篇文章给大家介绍如何使用runtime修改TextField文本框的占位文字颜色,有需要的可以参考借鉴.
收藏 0 赞 0 分享

iOS实现点击状态栏自动回到顶部效果详解

在IOS开发过程中,经常会有这种需求,需要通过点击状态栏返回到顶部,给用户更好的体验效果,下面这篇文章给大家详细介绍了实现过程,有需要的可以参考借鉴。
收藏 0 赞 0 分享

IOS上iframe的滚动条失效的解决办法

这篇文章主要为大家详细介绍了IOS上iframe的滚动条失效的解决办法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

IOS面试大全之常见算法

之前看了很多面试题,感觉要不是不够就是过于冗余,于是我将网上的一些面试题进行了删减和分类,这篇文章先给大家分享一下IOS中的常见算法,有需要的可以参考借鉴。
收藏 0 赞 0 分享

IOS判断字符串是否有空格实例

在我们大家日常开发的时候,经常会需要对注册,登录,忘记密码等功能的密码进行判断是否包含空格,下面这篇文章给大家分享了自己封装的一个方法,有需要的可以参考借鉴。
收藏 0 赞 0 分享

IOS设置按钮为圆角的示例代码

这篇文章给大家分享了IOS按钮设置为圆角的方法,按钮的四个角都可随意设置为圆角,对大家开发IOS具有一定的参考借鉴价值。有需要的朋友们可以参考借鉴。
收藏 0 赞 0 分享

IOS绘制虚线的方法总结

这篇文章给大家分享了iOS中绘制虚线常见的几种方式,大家可以根据自己的需求进行选择哪种方法,下面跟着小编来一起看看吧。
收藏 0 赞 0 分享

React Native搭建iOS开发环境

React Native的门槛不管是对于前端开发者还是移动端开发者来说都是很高的,既要懂原生又要懂js,技术栈是相当长的。但是没有关系,下面我们一步步来学习,慢慢成长吧!
收藏 0 赞 0 分享

IOS轻松几步实现自定义转场动画

这篇文章将讲述几个步骤实现转场动画的自定义方式,并且给出了示例代码,毕竟代码才是我们的语言,这样比较容易上手。下面来一起看看吧。
收藏 0 赞 0 分享
查看更多