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

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

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上实现的自定义仪表盘示例 的全部内容, 来源链接: utcz.com/z/325081.html

回到顶部