仪表盘绘制

仪表盘UI界面可以分为两部分

1 - 表盘刻度：
``````刻度是一段段短线，我使用的是 UIBezierPath + CAShapeLayer 绘制而成。

``````
2 - 绘制指针，实现指针旋转动画：
``````UIBezierPath + CAShapeLayer 绘制指针箭头
CABasicAnimation 实现指针旋转动画，要实现指针绕底部旋转，需要改变指针的锚点（anchorPoint属性）
``````

代码解析

计算公式：
Ax = cos(k) * L
``````- (void)addLineWithIndex:(NSInteger ) index{
CGFloat boldRadio = 0.86;//【大刻度 粗线】 线的起点到坐标原点的距离 / 线长
CGFloat thinRadio = 0.95;//【小刻度 细线】 线的起点到坐标原点的距离 / 线长
CGFloat L = self.frame.size.width * 0.5 - 10;
CGFloat arc = 5*(index / 180.0 * M_PI);
CGFloat sinA = sin(arc);
CGFloat cosA = cos(arc);
CGFloat startY = sinA * L * ((index%2)?thinRadio:boldRadio);
CGFloat startX = cosA * L * ((index%2)?thinRadio:boldRadio);
CGFloat endY = sinA * L;
CGFloat endX = cosA * L;
CGPoint startPoint = CGPointMake(0.5 * self.frame.size.width - startX, 0.5 * self.frame.size.height - startY);
CGPoint endPoint = CGPointMake(0.5 * self.frame.size.width - endX, 0.5 * self.frame.size.height - endY);

UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:startPoint];
[path closePath];

CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
shapeLayer.lineWidth = ((index%2)?1:3);//改变线粗
shapeLayer.strokeColor = [UIColor colorWithRed:0.5 green:0.3 blue:index/36.0*1 alpha:1].CGColor;
shapeLayer.path = path.CGPath;
shapeLayer.lineCap = kCALineCapSquare;
}
``````

``````for (NSInteger i = 0; i < 2; i++) {
}
``````

``````- (void)draw{
for (CAShapeLayer *layer in self.shapeLayers) {
[layer removeFromSuperlayer];
}
[self.shapeLayers removeAllObjects];
[self drawLine:0];
//    [self drawPointLayer];
}

- (void)drawLine:(NSInteger) index{
__block NSInteger t = index;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.02 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
t++;
if (index < 36) {
[self drawLine:t];
}else{
}
});
}

- (void)addLineWithIndex:(NSInteger ) index{
CGFloat boldRadio = 0.86;//【大刻度 粗线】 线的起点到坐标原点的距离 / 线长
CGFloat thinRadio = 0.95;//【小刻度 细线】 线的起点到坐标原点的距离 / 线长
CGFloat L = self.frame.size.width * 0.5 - 10;
CGFloat arc = 5*(index / 180.0 * M_PI);
CGFloat sinA = sin(arc);
CGFloat cosA = cos(arc);
CGFloat startY = sinA * L * ((index%2)?thinRadio:boldRadio);
CGFloat startX = cosA * L * ((index%2)?thinRadio:boldRadio);
CGFloat endY = sinA * L;
CGFloat endX = cosA * L;
CGPoint startPoint = CGPointMake(0.5 * self.frame.size.width - startX, 0.5 * self.frame.size.height - startY);
CGPoint endPoint = CGPointMake(0.5 * self.frame.size.width - endX, 0.5 * self.frame.size.height - endY);

UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:startPoint];
[path closePath];

CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
shapeLayer.lineWidth = ((index%2)?1:3);
shapeLayer.strokeColor = [UIColor colorWithRed:0.5 green:0.3 blue:index/36.0*1 alpha:1].CGColor;
shapeLayer.path = path.CGPath;
shapeLayer.lineCap = kCALineCapSquare;
}
``````

绘制指针
``````- (void)drawPointLayer{
_pointView = [[UIView alloc] initWithFrame:CGRectMake(self.frame.size.width * 0.5 - 5, 0, 10, self.frame.size.height)];
_pointView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0];

UIBezierPath *path = [UIBezierPath bezierPath];
[path addArcWithCenter:CGPointMake(_pointView.frame.size.width * 0.5, _pointView.frame.size.height)
startAngle:0
endAngle:2 * M_PI
clockwise:YES];
[path addLineToPoint:CGPointMake(_pointView.frame.size.width * 0.5, _pointView.frame.size.height * 0.5 + 35)];
[path addLineToPoint:CGPointMake(_pointView.frame.size.width * 0.5 - 10, _pointView.frame.size.height)];
//    [path closePath];
_pointLayer = [[CAShapeLayer alloc] init];
_pointLayer.lineWidth = 3;
_pointLayer.strokeColor = [UIColor whiteColor].CGColor;
_pointLayer.path = path.CGPath;
_pointLayer.lineCap = kCALineCapSquare;
_pointView.layer.anchorPoint = CGPointMake(0.5, 1);
_arc = -0.5 * M_PI;
self.pointView.transform = CGAffineTransformRotate(self.pointView.transform, _arc);
}
``````
实现指针动画
``````- (void)setProgress:(CGFloat)progress{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
animation.duration = 1;
animation.repeatCount = 1;
animation.fromValue = [NSNumber numberWithFloat:_arc];
_arc += (progress - _progress) * M_PI;
animation.toValue = [NSNumber numberWithFloat:_arc];
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
_progress = progress;
}
``````
注意：这里动画实现不能用transform实现，因为transform实现旋转动画时，会抄近路，当旋转角度大于180°时，旋转效果就有问题了。

• 序言：七十年代末，一起剥皮案震惊了整个滨河市，随后出现的几起案子，更是在滨河造成了极大的恐慌，老刑警刘岩，带你破解...
沈念sama阅读 81,413评论 1 177
• 序言：滨河连续发生了三起死亡事件，死亡现场离奇诡异，居然都是意外死亡，警方通过查阅死者的电脑和手机，发现死者居然都...
沈念sama阅读 28,415评论 1 144
• 文/潘晓璐 我一进店门，熙熙楼的掌柜王于贵愁眉苦脸地迎上来，“玉大人，你说我怎么就摊上这事。” “怎么了？”我有些...
开封第一讲书人阅读 33,175评论 0 105
• 文/不坏的土叔 我叫张陵，是天一观的道长。 经常有香客问我，道长，这世上最难降的妖魔是什么？ 我笑而不...
开封第一讲书人阅读 18,041评论 0 90
• 正文 为了忘掉前任，我火速办了婚礼，结果婚礼上，老公的妹妹穿的比我还像新娘。我一直安慰自己，他们只是感情好，可当我...
茶点故事阅读 23,316评论 0 148
• 文/花漫 我一把揭开白布。 她就那样静静地躺着，像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上，一...
开封第一讲书人阅读 19,223评论 1 88
• 那天，我揣着相机与录音，去河边找鬼。 笑死，一个胖子当着我的面吹牛，可吹牛的内容都是我干的。 我是一名探鬼主播，决...
沈念sama阅读 11,935评论 2 165
• 文/苍兰香墨 我猛地睁开眼，长吁一口气：“原来是场噩梦啊……” “哼！你这毒妇竟也来了？” 一声冷哼从身侧响起，我...
开封第一讲书人阅读 11,327评论 0 80
• 想象着我的养父在大火中拼命挣扎，窒息，最后皮肤化为焦炭。我心中就已经是抑制不住地欢快，这就叫做以其人之道，还治其人...
爱写小说的胖达阅读 9,855评论 5 114
• 序言：老挝万荣一对情侣失踪，失踪者是张志新（化名）和其女友刘颖，没想到半个月后，有当地人在树林里发现了一具尸体，经...
沈念sama阅读 13,106评论 0 130
• 正文 独居荒郊野岭守林人离奇死亡，尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
茶点故事阅读 11,833评论 1 128
• 正文 我和宋清朗相恋三年，在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
茶点故事阅读 12,687评论 0 133
• 白月光回国，霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前， 不然我有一百种方法让你生不如死。]我...
爱写小说的胖达阅读 7,469评论 0 18
• 序言：一个原本活蹦乱跳的男人离奇死亡，死状恐怖，灵堂内的尸体忽然破棺而出，到底是诈尸还是另有隐情，我是刑警宁泽，带...
沈念sama阅读 10,280评论 2 119
• 正文 年R本政府宣布，位于F岛的核电站，受9级特大地震影响，放射性物质发生泄漏。R本人自食恶果不足惜，却给世界环境...
茶点故事阅读 13,466评论 3 128
• 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹，春花似锦、人声如沸。这庄子的主人今日做“春日...
开封第一讲书人阅读 9,056评论 0 3
• 文/苍兰香墨 我抬头看了看天上的太阳。三九已至，却和暖如春，着一层夹袄步出监牢的瞬间，已是汗流浃背。 一阵脚步声响...
开封第一讲书人阅读 9,330评论 0 79
• 我被黑心中介骗来泰国打工， 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留，地道东北人。 一个月前我还...
沈念sama阅读 14,016评论 2 137
• 正文 我出身青楼，却偏偏与公主长得像，于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子，可洞房花烛夜当晚...
茶点故事阅读 14,514评论 2 134