ios制作一个速度表盘

我们首先看一下这个速度表盘的效果:

速度表盘

为了实现上述的效果,我们首当其冲的是得了解的是贝塞尔曲线,听上去好高大上的样子,接下来我先就我了解贝塞尔曲线的知识给未接触的朋友普及一下。

Bézier curve(贝塞尔曲线)是应用于二维图形应用程序的数学曲线.主要有起始点、终止点(也称锚点)、控制点这几个概念。通过调整控制点,贝塞尔曲线的形状会发生变化。

大家先欣赏一下各种贝塞尔曲线

一阶

一阶

二阶

二阶

三阶

三阶

高阶

高阶
  • 我们要完成上述表盘的效果,需要用到的就是贝塞尔曲线!
    我们看一下苹果官方文档对它的介绍

The UIBezierPath class lets you define a path consisting of straight and curved line segments and render that path in your custom views. You use this class initially to specify just the geometry for your path. Paths can define simple shapes such as rectangles, ovals, and arcs or they can define complex polygons that incorporate a mixture of straight and curved line segments. After defining the shape, you can use additional methods of this class to render the path in the current drawing context.

上述文字简单翻译一下的意思是:你可以使用贝塞尔曲线来定义直线和曲线和自定义的图形。官方还有很长的篇幅来解释它,有兴趣的可以去看。
下面我主要介绍UIBezierPathCAShapeLayer一起使用,完成上述表盘的效果,我默认你已经经过查找资料对他们很熟悉。

首先我们分解步骤

  • 1.画出内侧的圆弧


    屏幕快照 2016-06-21 下午3.16.07.png

苹果官方提供了3阶以下的api接口,我使用一个二阶的api,实现圆弧。

    //主要解释一下各个参数的意思
    //center  中心点(可以理解为圆心)
    //radius  半径
    //startAngle 起始角度
    //endAngle  结束角度
    //clockwise  是否顺时针
    UIBezierPath *cicrle     = [UIBezierPath bezierPathWithArcCenter:centers
                                                              radius:95
                                                              startAngle:- M_PI
                                                              endAngle: 0
                                                              clockwise:YES];
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.lineWidth     = 5.f;
    shapeLayer.fillColor     = [UIColor clearColor].CGColor;
    shapeLayer.strokeColor   = RGBColor(185,243,110).CGColor;
    shapeLayer.path          = cicrle.CGPath;
    
    [self.layer addSublayer:shapeLayer];

弧线的参考系:


coordinate system
  • 2.画出外侧的刻度

  CGFloat perAngle = M_PI / 50;
//我们需要计算出每段弧线的起始角度和结束角度
//这里我们从- M_PI 开始,我们需要理解与明白的是我们画的弧线与内侧弧线是同一个圆心
  for (int i = 0; i< 51; i++) {
        
        CGFloat startAngel = (-M_PI + perAngle * i);
        CGFloat endAngel   = startAngel + perAngle/5;

        UIBezierPath *tickPath = [UIBezierPath bezierPathWithArcCenter:centers radius:150 startAngle:startAngel endAngle:endAngel clockwise:YES];
        CAShapeLayer *perLayer = [CAShapeLayer layer];
        
        if (i % 5 == 0) {
            
            perLayer.strokeColor = [UIColor colorWithRed:0.62 green:0.84 blue:0.93 alpha:1.0].CGColor;
            perLayer.lineWidth   = 10.f;
            
        }else{
            perLayer.strokeColor = [UIColor colorWithRed:0.22 green:0.66 blue:0.87 alpha:1.0].CGColor;
            perLayer.lineWidth   = 5;
            
        }
        
        perLayer.path = tickPath.CGPath;
        [self.layer addSublayer:perLayer];
        
    }

  • 3.增加刻度值

需要使用创建label的方式,首先我们得计算出label的position,然后添加

 CGPoint point      = [self calculateTextPositonWithArcCenter:centers Angle:textAngel];
            NSString *tickText = [NSString stringWithFormat:@"%d",i * 2];
            
            //默认label的大小14 * 14
            UILabel *text      = [[UILabel alloc] initWithFrame:CGRectMake(point.x - 5, point.y - 5, 14, 14)];
            text.text          = tickText;
            text.font          = font;
            text.textColor     = [UIColor colorWithRed:0.54 green:0.78 blue:0.91 alpha:1.0];
            text.textAlignment = NSTextAlignmentCenter;
            [self addSubview:text];
//默认计算半径135
- (CGPoint)calculateTextPositonWithArcCenter:(CGPoint)center
                                       Angle:(CGFloat)angel
{
    CGFloat x = 135 * cosf(angel);
    CGFloat y = 135 * sinf(angel);

    return CGPointMake(center.x + x, center.y - y);
}
  • 4.实现速度显示(实现方式很多,可以是Label,也可以画出来,就不赘述)

这里说一下画的方式

- (void)drawRect:(CGRect)rect
{
     NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIFont boldSystemFontOfSize:15],NSFontAttributeName,[UIColor whiteColor], NSForegroundColorAttributeName, nil];
    [@"km/h" drawInRect:CGRectMake(centers.x - 15, centers.y, 60, 20) withAttributes:attributes];
}

  • 5.实现进度
// 进度的曲线
    UIBezierPath *progressPath  = [UIBezierPath bezierPathWithArcCenter:centers
                                                                radius:120
                                                                startAngle:- M_PI
                                                                endAngle:0
                                                                clockwise:YES];
                  progressLayer = [CAShapeLayer layer];
    progressLayer.lineWidth     =  50.f;
    progressLayer.fillColor     = [UIColor clearColor].CGColor;
    progressLayer.strokeColor   =  RGBAColor(185,243,110,0.2).CGColor;
    progressLayer.path          = progressPath.CGPath;
    progressLayer.strokeStart   = 0;
    progressLayer.strokeEnd     = 0;

我们只需要改变strokeEnd即可实现速度变化,默认0~1之间。

//提供一个外部的接口,通过重写setter方法来改变进度

- (void)setSpeed:(double)speed
{
                     _speed = speed;
    progressLayer.strokeEnd = _speed? _speed/100:0;
    speedLabel.text = [NSString stringWithFormat:@"%.f",speed];
}

我们可以在外部通过定时器方法模拟速度表盘的变化,即可实现上述速度表盘。

结尾:本文只是简单的介绍一种思路,个人感觉可以优化的空间很多,打算整理写一个上传gitHub的三方库,提供多个可供外界改变的接口,希望有兴趣的朋友一起来做,维护这个库,欢迎私信联系。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容