美文网首页
绘制一条彩虹🌈

绘制一条彩虹🌈

作者: QuakOrigin | 来源:发表于2018-07-10 10:48 被阅读0次

    一般认为彩虹有七种颜色构成,赤橙黄绿青蓝紫,然后是弧形。
    显而易见,可以用 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 提供的解决办法。

    相关文章

      网友评论

          本文标题:绘制一条彩虹🌈

          本文链接:https://www.haomeiwen.com/subject/lfcfpftx.html