绘制一条彩虹🌈

一般认为彩虹有七种颜色构成,赤橙黄绿青蓝紫,然后是弧形。
显而易见,可以用 UIBezierPath 来绘制一条红色的扇形。
因为用的 iPhone7 的模拟器,所以可以把圆心设置在 180 的位置,半径 150 ,绘制扇形,显然需要两条圆弧来完成,半径相差 10

    UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(180, 250) radius:150 startAngle:M_PI endAngle:M_PI*2 clockwise:YES];
    [bezierPath addArcWithCenter:CGPointMake(180, 250) radius:140 startAngle:0 endAngle:M_PI clockwise:NO];
    [bezierPath closePath];
    
    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.path = bezierPath.CGPath;
    layer.fillColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:layer];

这里需要注意的就是第二条圆弧两个点的顺序,因为第一条是从左到右绘制的,所以需要第二条从右向左绘制,因为 [bezierPath closePath]; 这句代码是按顺序依次连接出现的各个顶点的。然后 clockwise:NO 反时钟方向绘制。

有了第一条,很容易得到下面的,当然需要创建多个 CALayer,首先需要一个 colors 的数组,为了简化,都用 UIColor 固有的属性。

   NSArray *colors = @[(__bridge id)[UIColor redColor].CGColor,
                        (__bridge id)[UIColor orangeColor].CGColor,
                        (__bridge id)[UIColor yellowColor].CGColor,
                        (__bridge id)[UIColor greenColor].CGColor,
                        (__bridge id)[UIColor cyanColor].CGColor,
                        (__bridge id)[UIColor blueColor].CGColor,
                        (__bridge id)[UIColor purpleColor].CGColor];

上循环😆

    for(int i=0; i<colors.count; i++) {
        UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(180, 250) radius:(150-10*i) startAngle:M_PI endAngle:M_PI*2 clockwise:YES];
        [bezierPath addArcWithCenter:CGPointMake(180, 250) radius:(140-10*i) startAngle:0 endAngle:M_PI clockwise:NO];
        [bezierPath closePath];
        
        CAShapeLayer *layer = [CAShapeLayer layer];
        layer.path = bezierPath.CGPath;
        layer.fillColor = (__bridge CGColorRef _Nullable)(colors[i]);
        [self.view.layer addSublayer:layer];
    }

我们得到了想要的彩虹🌈



简单实现,但是彩虹的颜色看起来很突兀,全都是色块叠加上去的,这显然不是很好的解决办法。

多重颜色渐变,很自然的会想到 CAGradientLayer ,作为 CALayer 的子类,它能轻松的实现多种颜色的组合渐变。

先绘简单的一条彩虹条线。

    CAGradientLayer *layer = [CAGradientLayer layer];
    layer.frame = CGRectMake(30, 130, 150, 1);
    [self.view.layer addSublayer:layer];
        
    layer.colors = colors;
    layer.locations = @[@(1/7.0), @(2/7.0), @(3/7.0), @(4/7.0), @(5/7.0), @(6/7.0), @1.0];
    layer.startPoint = CGPointMake(0, 0);
    layer.endPoint = CGPointMake(1, 0);

locations 代表了每个色值绘制的区域范围,这里做了个平均,可以调整显示比例,而且 locationscount 必须要与 colorscount保持一致,否则可能会得到空白。 startPointendPoint 两个参数代表了起始的坐标点,这里纵坐标不变都是 0 表示只做横向渐变,如果改成 layer.endPoint = CGPointMake(1, 1); 则会对角渐变。

发现彩虹属于弧形渐变,以某一圆点为中心的射线渐变,CAGradientLayer 属于矩形渐变,不能放射状展示渐变效果,对角渐变也无法得到我们想要的结果。

消耗性能的逐条绘制
    for(int i=0; i<180; i++) {
        CAGradientLayer *layer = [CAGradientLayer layer];
        layer.frame = CGRectMake(50, 250, 70, 1);
        [self.view.layer addSublayer:layer];
        
        layer.colors = colors;
        layer.locations = @[@(1/7.0), @(2/7.0), @(3/7.0), @(4/7.0), @(5/7.0), @(6/7.0), @1.0];
        layer.startPoint = CGPointMake(0, 0);
        layer.endPoint = CGPointMake(1, 0);
    
        layer.affineTransform = CGAffineTransformMakeRotation(M_PI/180.0*i);
        layer.anchorPoint = CGPointMake(1, 0.5);
    }

我们得到了这样的图形


显然跟我们想要的图案相差甚远,首先是需要设置图像的锚点,因为想法是图像能绕一个圆点进行旋转,而 layer.anchorPoint 是一个[(0,0), (1,1)] 区间的值,表示视图从左下角到右上角的一个区间,显然无法设置到视图外的某点。 而且一个像素点逐行绘制会造成锯齿现象比较严重,

/* Defines the anchor point of the layer's bounds rect, as a point in
 * normalized layer coordinates - '(0, 0)' is the bottom left corner of
 * the bounds rect, '(1, 1)' is the top right corner. Defaults to
 * '(0.5, 0.5)', i.e. the center of the bounds rect. Animatable. */

@property CGPoint anchorPoint;

想要使用这点,需要修改 colors ,手动加上白色或者透明色块,然后修改每一条的高度。

    NSArray *colors = @[(__bridge id)[UIColor redColor].CGColor,
                        (__bridge id)[UIColor orangeColor].CGColor,
                        (__bridge id)[UIColor yellowColor].CGColor,
                        (__bridge id)[UIColor greenColor].CGColor,
                        (__bridge id)[UIColor cyanColor].CGColor,
                        (__bridge id)[UIColor blueColor].CGColor,
                        (__bridge id)[UIColor purpleColor].CGColor,
                        (__bridge id)[UIColor clearColor].CGColor,
                        (__bridge id)[UIColor clearColor].CGColor];
    
    for(int i=0; i<180; i++) {
        CAGradientLayer *layer = [CAGradientLayer layer];
        layer.frame = CGRectMake(100, 250, 150, 4);
        [self.view.layer addSublayer:layer];
        
        layer.colors = colors;
        layer.locations = @[@(1/14.0), @(2/14.0), @(3/14.0), @(4/14.0), @(5/14.0), @(6/14.0), @0.5, @(8/14.0), @1];
        layer.startPoint = CGPointMake(0, 0);
        layer.endPoint = CGPointMake(1, 0);
    
        layer.affineTransform = CGAffineTransformMakeRotation(M_PI/180.0*i);
        layer.anchorPoint = CGPointMake(1, 0.5);
    }

可以看出效果已经比之前平滑多了。

细心的朋友可能已经发现,为什么 [UIColor clearColor] 需要设置两次,因为渐变色是两个值之间发生的,如果只加一个,那么最后一段就变成了 [UIColor purpleColor][UIColor clearColor] 的渐变,看到的将会是紫色到透明的渐变,最后得到弧形很小,甚至是半圆。如果设置的是同色渐变,那么渐变效果就会失效。

还有一点就是图中的 frame.origin.x 设置了 100 但是模拟器中显示出来的显然没有这么多,这是因为修改了 layer 层的 anchorPoint,修改视图的 anchorPoint 会造成视图的 bounds 修改。

/* The position in the superlayer that the anchor point of the layer's
 * bounds rect is aligned to. Defaults to the zero point. Animatable. */

@property CGPoint position;

当你设置图层的frame属性的时候,position 点的位置(也就是 position 坐标)根据锚点(anchorPoint)的值来确定,而当你设置图层的position属性的时候,bounds 的位置(也就是 frameorgin 坐标)会根据锚点(anchorPoint)来确定。

根据上面说明,只需要在设置完视图的 layer.anchorPoint 之后,重新设置下 layer.frame 就可以解决视图位置问题了。

        layer.anchorPoint = CGPointMake(1, 0.5);
        layer.frame = CGRectMake(30, 250, 150, 4);

感谢: lvyong彻底理解position与anchorPoint 提供的解决办法。

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

推荐阅读更多精彩内容