IOS自定义仪表盘


版权声明:本文为博主原创文章,未经博主允许不得转载。
【原创作品, 欢迎转载,转载请在明显处注明! 谢谢。
原文地址:http://blog.csdn.net/toss156/article/details/7407770】
今天给大家带来一个自定义的仪表盘,效果图如下。
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 来实现旋转的话,它默认是以最小的旋转的,如果要实现控制旋转的方向的话,我们就只能用关键帧来设置旋转的路径。用关键帧的好处还有一个,就是可以给指针添加,旋转到指定位置以后的左右摆动的效果。
绘制仪表盘是通过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
IOS自定义仪表盘的更多相关文章
- 【iOS自定义键盘及键盘切换】详解
[iOS自定义键盘]详解 实现效果展示: 一.实现的协议方法代码 #import <UIKit/UIKit.h> //创建自定义键盘协议 @protocol XFG_KeyBoardDel ...
- iOS自定义的UISwitch按钮
UISwitch开关控件 开关代替了点选框.开关是到目前为止用起来最简单的控件,不过仍然可以作一定程度的定制化. 一.创建 UISwitch* mySwitch = [[ UISwitchalloc] ...
- 如何实现 iOS 自定义状态栏
给大家介绍如何实现 iOS 自定义状态栏 Sample Code: 01 UIWindow * statusWindow = [[UIWindow alloc] initWithFrame:[UIAp ...
- iOS自定义组与组之间的距离以及视图
iOS自定义组与组之间的距离以及视图 //头视图高度 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(N ...
- iOS 自定义转场动画
代码地址如下:http://www.demodashi.com/demo/12955.html 一.总效果 本文记录分享下自定义转场动画的实现方法,具体到动画效果:新浪微博图集浏览转场效果.手势过渡动 ...
- iOS 自定义转场动画浅谈
代码地址如下:http://www.demodashi.com/demo/11612.html 路漫漫其修远兮,吾将上下而求索 前记 想研究自定义转场动画很久了,时间就像海绵,挤一挤还是有的,花了差不 ...
- iOS自定义转场动画实战讲解
iOS自定义转场动画实战讲解 转场动画这事,说简单也简单,可以通过presentViewController:animated:completion:和dismissViewControllerA ...
- IOS自定义表格UITableViewCell
在UITableView中,自定义表格,最原始是继承UITableViewCell,然后通过写代码方式去搞,但是这个费事了. 1.在storyboard中 给一个ViewController的tabi ...
- ios 自定义键盘
由于项目需要,需要自定义键盘.ios系统键盘会缓存键盘输入,并保存在系统目录下的文件里,并且是明文存储,存在帐号密码泄漏风险.在别人代码基础上修改了下,美化了下界面,去掉了字符输入,加了点击特效,截图 ...
随机推荐
- java经典小算法
package com.shb.java; public class Demo4 { /**时间有限 先不写文字了 自己随便敲的 * @param args * @author shaobn */ p ...
- RMAN备份演练进阶篇
前篇介绍了通过rman进行各种备份,进阶篇则主要是rman的一些功能扩展和增加功能,利用前篇你已经完全可以完成数据库的备份,而通过本篇你可以更好更方便的完成数据库的备份. 一.建立增量备份 如果数据库 ...
- 白盒测试的学习之路----(五)TestNG的参数分离
之前的测试用例直接嵌套在代码中,不便于维护和测试设计,应该单独把测试用例放在excel内,然后程序从中读取数据到相应的接口内即可.使用ava程序对Microsoft Office格式档案读和写的功能提 ...
- 「thunar」给thunar增加搜索文件功能
1.安装catfish sudo apt-get install catfish 2.配置thunar,添加[自定义动作] 打开 Thunar 后,点击 Edit -> Configure cu ...
- 对DotNet分布式应用搭建的考虑
设计前的考虑和准备工作 1 对业务需求的理解重要性远远胜于对技术架构的理解 2 架构包含技术架构和业务架构 3 没有万能和通用的架构,只有符合自身业务需求的架构 4 架构本身的复杂性要截至在架构设计阶 ...
- Java如何对ArrayList里的元素排序
- Tomcat端口被占用快速解决方案
在dos下,输入 netstat -ano|findstr 8080 //说明:查看占用8080端口的进程 显示占用端口的进程 taskkill /pid 6856 /f //说明,运行 ...
- 【python cookbook】【数据结构与算法】16.筛选序列中的元素
问题:提取出序列中的值或者根据某些标准对序列做删减 解决方案:列表推导式.生成器表达式.使用内建的filter()函数 1.列表推导式方法:存在一个潜在的缺点,如果输入数据非常大可能会产生一个庞大的结 ...
- iOS的通知Notification
这里是不同的对象之间的通知, 不是本地通知. 一开始玩, 很挠头, 后来发现原来只是对象init的过程出了问题. 首先, 新建一个简单的单controller的工程. 然后打开它的ViewContro ...
- Java中删除指定文件夹文件夹下面有内容也删除使用递归方案
import java.io.File; import java.text.ParseException; import java.text.SimpleDateFormat; import java ...