分類:
版權聲明:本文爲博主原創文章,未經博主容許不得轉載。ios
【原創做品, 歡迎轉載,轉載請在明顯處註明! 謝謝。app
原文地址:http://blog.csdn.net/toss156/article/details/7407770】框架
今天給你們帶來一個自定義的儀表盤,效果圖以下。iview
Demo中用到了 QuartzCore類 首先繼承一個UIView。函數
- <span style="font-size:10px;">//
- // 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</span><span style="font-size: 14px;">
- </span>
指針的旋轉是經過QuartzCore.framework中的CATransform3DRotate 來實現的,因此必定要記得把框架添加進來。固然在旋轉以前,咱們還須要把指針的中心pointer.layer.anchorPoint 移動到你須要的轉動中心。
在設置旋轉動畫的時候,咱們用的不是CABaseAnimiation 而是用 CAKeyframeAnimation。這是由於若是使用中的 toValue 來實現旋轉的話,它默認是以最小的旋轉的,若是要實現控制旋轉的方向的話,咱們就只能用關鍵幀來設置旋轉的路徑。用關鍵幀的好處還有一個,就是能夠給指針添加,旋轉到指定位置之後的左右擺動的效果。oop
繪製儀表盤是經過Quartz2D來實現的,首先咱們須要用UIGraphicsGetCurrentContext函數來獲取一個Context上下文,就是至關於獲取一個畫布。而後就能夠在上面經過三角函數的計算,畫出背景圖片,和上面的刻度線了。post
- //
- // 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://download.csdn.net/detail/toss156/4183721