服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - IOS上实现的自定义仪表盘示例

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

2021-03-03 15:35念风2012 IOS

本篇文章主要介绍了IOS上实现的自定义仪表盘示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

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

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

demo中用到了 quartzcore类 首先继承一个uiview。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 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上下文,就是相当于获取一个画布。然后就可以在上面通过三角函数的计算,画出背景图片,和上面的刻度线了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
// 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的下载地址:gaugedemo.rar

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

原文链接:http://blog.csdn.net/toss156/article/details/7407770

延伸 · 阅读

精彩推荐
  • IOSiOS逆向教程之logify跟踪方法的调用

    iOS逆向教程之logify跟踪方法的调用

    这篇文章主要给大家介绍了关于iOS逆向教程之logify跟踪方法调用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学...

    Mr.Guo11472021-04-28
  • IOSiOS APP实现微信H5支付示例总结

    iOS APP实现微信H5支付示例总结

    这篇文章主要介绍了iOS APP实现微信H5支付示例总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    一张小A11332021-06-01
  • IOSiOS中时间与时间戳的相互转化实例代码

    iOS中时间与时间戳的相互转化实例代码

    这篇文章主要介绍了iOS中时间与时间戳的相互转化实例代码,非常具有实用价值,需要的朋友可以参考下。...

    张无忌!4812021-03-09
  • IOSiOS10 Xcode8适配7个常见问题汇总

    iOS10 Xcode8适配7个常见问题汇总

    这篇文章主要为大家详细汇总了iOS10 Xcode8适配7个常见问题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    索马里猫10332021-02-01
  • IOS谈一谈iOS单例模式

    谈一谈iOS单例模式

    这篇文章主要和大家谈一谈iOS中的单例模式,单例模式是一种常用的软件设计模式,想要深入了解iOS单例模式的朋友可以参考一下...

    彭盛凇11872021-01-19
  • IOSxcode8提交ipa失败无法构建版本问题的解决方案

    xcode8提交ipa失败无法构建版本问题的解决方案

    xcode升级到xcode8后发现构建不了新的版本。怎么解决呢?下面小编给大家带来了xcode8提交ipa失败无法构建版本问题的解决方案,非常不错,一起看看吧...

    Cinna丶7542021-02-03
  • IOSiOS常见的几个修饰词深入讲解

    iOS常见的几个修饰词深入讲解

    这篇文章主要给大家介绍了关于iOS常见的几个修饰词的相关资料,iOS修饰词包括assign、weak、strong、retain、copy、nonatomic、atomic、readonly、readwrite,文中通过示...

    郡王丶千夜7422021-05-10
  • IOSIOS网络请求之AFNetWorking 3.x 使用详情

    IOS网络请求之AFNetWorking 3.x 使用详情

    本篇文章主要介绍了IOS网络请求之AFNetWorking 3.x 使用详情,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    总李写代码6892021-03-04