IOS上實(shí)現(xiàn)的自定義儀表盤示例
今天給大家?guī)硪粋€(gè)自定義的儀表盤,效果圖如下。

Demo中用到了 QuartzCore類 首先繼承一個(gè)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
指針的旋轉(zhuǎn)是通過QuartzCore.framework中的CATransform3DRotate 來實(shí)現(xiàn)的,所以一定要記得把框架添加進(jìn)來。當(dāng)然在旋轉(zhuǎn)之前,我們還需要把指針的中心pointer.layer.anchorPoint 移動(dòng)到你需要的轉(zhuǎn)動(dòng)中心。
在設(shè)置旋轉(zhuǎn)動(dòng)畫的時(shí)候,我們用的不是CABaseAnimiation 而是用 CAKeyframeAnimation。這是因?yàn)槿绻褂弥械?toValue 來實(shí)現(xiàn)旋轉(zhuǎn)的話,它默認(rèn)是以最小的旋轉(zhuǎn)的,如果要實(shí)現(xiàn)控制旋轉(zhuǎn)的方向的話,我們就只能用關(guān)鍵幀來設(shè)置旋轉(zhuǎn)的路徑。用關(guān)鍵幀的好處還有一個(gè),就是可以給指針添加,旋轉(zhuǎn)到指定位置以后的左右擺動(dòng)的效果。
繪制儀表盤是通過Quartz2D來實(shí)現(xiàn)的,首先我們需要用UIGraphicsGetCurrentContext函數(shù)來獲取一個(gè)Context上下文,就是相當(dāng)于獲取一個(gè)畫布。然后就可以在上面通過三角函數(shù)的計(jì)算,畫出背景圖片,和上面的刻度線了。
// 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
/************************************************
儀表盤的大小不建議設(shè)置的太小。
長(zhǎng)寬都是300是最適合的
如果要更小的需要自行修改刻度長(zhǎng)度和文字大小
---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) {
//設(shè)置背景透明
[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];
//設(shè)置文字標(biāo)簽
[self setTextLabel:CELLNUM];
//設(shè)置指針到0位置
pointer.layer.transform = CATransform3DMakeRotation([self transToRadian:-MAXOFFSETANGLE], 0, 0, 1);
}
return self;
}
/*
* setTextLabel 繪制刻度值
* @labelNum NSInteger 刻度值的數(shù)目
*/
-(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];
//設(shè)置刻度的文字的格式
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];
}
// 設(shè)置刻度表的名稱
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 繪制刻度的標(biāo)記
* @labelNum NSInteger 刻度是數(shù)目
*/
-(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;
//給刻度標(biāo)記繪制不同的顏色
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]);
}
//繪制不同的長(zhǎng)短的刻度
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 移動(dòng)到某個(gè)數(shù)值
* @value CGFloat 移動(dòng)到的數(shù)值
* @isAnim BOOL 是否執(zhí)行動(dòng)畫
*/
-(void)setGaugeValue:(CGFloat)value animation:(BOOL)isAnim
{
CGFloat tempAngle = [self parseToAngle:value];
gaugeValue = value;
//設(shè)置轉(zhuǎn)動(dòng)時(shí)間和轉(zhuǎn)動(dòng)動(dòng)畫
if(isAnim){
[self pointToAngle:tempAngle Duration:0.6f];
}else
{
[self pointToAngle:tempAngle Duration:0.0f];
}
}
/*
* pointToAngle 按角度旋轉(zhuǎn)
* @angel CGFloat 角度
* @duration CGFloat 動(dòng)畫執(zhí)行時(shí)間
*/
- (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;
//設(shè)置轉(zhuǎn)動(dòng)路徑,不能直接用 CABaseAnimation 的toValue,那樣是按最短路徑的,轉(zhuǎn)動(dòng)超過180度時(shí)無法控制方向
int i = 1;
for(;i<=10;i++){
[values addObject:[NSValue valueWithCATransform3D:CATransform3DRotate(CATransform3DIdentity, [self transToRadian:(gaugeAngle+distance*i)], 0, 0, 1)]];
}
//添加緩動(dòng)效果
[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 角度轉(zhuǎn)弧度
* @angel CGFloat 角度
*/
-(CGFloat)transToRadian:(CGFloat)angel
{
return angel*M_PI/180;
}
/*
* parseToX 根據(jù)角度,半徑計(jì)算X坐標(biāo)
* @radius CGFloat 半徑
* @angle CGFloat 角度
*/
- (CGFloat) parseToX:(CGFloat) radius Angle:(CGFloat)angle
{
CGFloat tempRadian = [self transToRadian:angle];
return radius*cos(tempRadian);
}
/*
* parseToY 根據(jù)角度,半徑計(jì)算Y坐標(biāo)
* @radius CGFloat 半徑
* @angle CGFloat 角度
*/
- (CGFloat) parseToY:(CGFloat) radius Angle:(CGFloat)angle
{
CGFloat tempRadian = [self transToRadian:angle];
return radius*sin(tempRadian);
}
/*
* parseToAngle 根據(jù)數(shù)據(jù)計(jì)算需要轉(zhuǎn)動(dòng)的角度
* @val CGFloat 要移動(dòng)到的數(shù)值
*/
-(CGFloat) parseToAngle:(CGFloat) val
{
//異常的數(shù)據(jù)
if(val<minNum){
return minNum;
}else if(val>maxNum){
return maxNum;
}
CGFloat temp =(val-gaugeValue)*angleperValue;
return temp;
}
/*
* parseToValue 根據(jù)角度計(jì)算數(shù)值
* @val CGFloat 要移動(dòng)到的角度
*/
-(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();
//設(shè)置背景透明
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
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
iOS多線程應(yīng)用開發(fā)中使用NSOperation類的基本方法
這篇文章主要介紹了iOS多線程應(yīng)用開發(fā)中使用NSOperation類的基本方法,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2015-11-11
iOS開發(fā)之統(tǒng)計(jì)Xcode工程的代碼行數(shù)
這篇文章主要給大家介紹了在iOS開發(fā)中,如果想要統(tǒng)計(jì)Xcode工程的代碼行數(shù)該如何實(shí)現(xiàn),文章給出了詳細(xì)的方法和示例代碼,對(duì)大家的理解和學(xué)習(xí)很有幫助,本文中還分享了統(tǒng)計(jì)java文件和xml文件的代碼,有需要的朋友們下面來一起看看吧。2016-10-10
iOS驗(yàn)證手機(jī)號(hào)的正則表達(dá)式
這篇文章主要為大家詳細(xì)介紹了iOS驗(yàn)證手機(jī)號(hào)的正則表達(dá)式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
iOS實(shí)現(xiàn)支持小數(shù)的星星評(píng)分組件實(shí)例代碼
程序中需要打分的功能,在網(wǎng)上找了幾個(gè),都不是很滿意。所以自己動(dòng)手實(shí)現(xiàn)了一個(gè),下面這篇文章主要給大家介紹了關(guān)于利用iOS實(shí)現(xiàn)支持小數(shù)的星星評(píng)分組件的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-08-08
iOS自定義UITableView實(shí)現(xiàn)不同系統(tǒng)下的左滑刪除功能詳解
關(guān)于左滑刪除這塊,相信不少朋友都遇到過。下面這篇文章主要給大家介紹了關(guān)于iOS如何自定義UITableView實(shí)現(xiàn)不同系統(tǒng)下的左滑刪除功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-09-09
iOS使用pageViewController實(shí)現(xiàn)多視圖滑動(dòng)切換
這篇文章主要為大家詳細(xì)介紹了iOS使用pageViewController實(shí)現(xiàn)多視圖滑動(dòng)切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
詳解IOS圖層轉(zhuǎn)場(chǎng)動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了IOS圖層轉(zhuǎn)場(chǎng)動(dòng)畫, CATransition類實(shí)現(xiàn)層的轉(zhuǎn)場(chǎng)動(dòng)畫,能夠?yàn)閷犹峁┮瞥銎聊缓鸵迫肫聊坏膭?dòng)畫效果,感興趣的小伙伴們可以參考一下2016-02-02

