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

原文地址::https://www.jb51.net/article/103817.htm

相关文章

1、手把手教你玩转iOS的仪表盘----https://blog.csdn.net/darrenzzb66/article/details/52511077

2、iOS非常漂亮的全代码绘制的仪表盘----https://download.csdn.net/download/haohaohaohaohao00000/8946029

3、iOS开发——仪表盘的制作----https://www.cnblogs.com/qinxiaoguang/p/5441536.html

4、利用贝塞尔曲线绘制(UIBezierPath)自定义iOS动态速度表,可以自定义刻度,刻度值,进度条样式----https://www.cnblogs.com/luerniu/p/5808854.html

5、IOS上实现的自定义仪表盘(可以用在流量监控之类的应用上)----https://blog.csdn.net/u014468600/article/details/23198699

6、ios制作一个仪表盘----https://blog.csdn.net/waterseason/article/details/84918625

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

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的下载地址:http://xiazai.jb51.net/201701/yuanma/GaugeDemo_jb51.rar

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

您可能感兴趣的文章:

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

猜你喜欢

转载自blog.csdn.net/xqhrs232/article/details/87937903