Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIBezierPath with color gradient

I've got an question about UIBezierPath.

For example I've got this path:

Now I want to have a color gradient from white to red. From left to right.

Here is my code:

UIBezierPath *bezierPath;
bezierPath = [UIBezierPath bezierPathWithArcCenter:_center radius:_radius startAngle:((4 * angle)) endAngle:(((20) * angle)) clockwise:YES];
[bezierPath addLineToPoint:_center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:0/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];

Can anyone help me?

Edit 1:

I have this color wheel:

enter image description here

    UIBezierPath *bezierPath;

for ( int i = 0; i < 360; i++) {
    bezierPath = [UIBezierPath bezierPathWithArcCenter:_center radius:_radius startAngle:((i * angle)) endAngle:(((i + 1) * angle)) clockwise:YES];

    [bezierPath addLineToPoint:_center];
    [bezierPath closePath];
    UIColor *color = [UIColor colorWithHue:i/sectors saturation:1. brightness:1. alpha:1];
    [color setFill];
    [color setStroke];
    [bezierPath fill];
    [bezierPath stroke];
}

but I want this: (With the white Gradient)

enter image description here

like image 325
Daniel Christoph Avatar asked Aug 20 '15 12:08

Daniel Christoph


4 Answers

you can give it a try :)

- (void)drawRect:(CGRect)rect
{
    CGFloat arcStep = (M_PI *2) / 360; // M_PI*2 is equivalent of full cirle
    BOOL clocklwise = NO;
    CGFloat x = CGRectGetWidth(rect) / 2; // circle's center
    CGFloat y = CGRectGetHeight(rect) / 2; // circle's center
    CGFloat radius = MIN(x, y) / 2;
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // draw colorful circle
    CGContextSetLineWidth(ctx, radius*2);
    for (CGFloat i = 0; i < 360; i+=1)
    {
        UIColor* c = [UIColor colorWithHue:i/360 saturation:1. brightness:1. alpha:1];

        CGContextSetStrokeColorWithColor(ctx, c.CGColor);

        CGFloat startAngle = i * arcStep;
        CGFloat endAngle = startAngle + arcStep + 0.02;

        CGContextAddArc(ctx, x, y, radius, startAngle, endAngle, clocklwise);
        CGContextStrokePath(ctx);
    }
    // drawing circles then, you might want few of them - smaller radius and less alpha with each step
    UIColor* c = [[UIColor whiteColor] colorWithAlphaComponent: 0.03];
    for (CGFloat fillRadius = radius/2; fillRadius > 0; fillRadius -= 1.f)
    {
        CGContextSetLineWidth(ctx, fillRadius*2);
        CGContextSetStrokeColorWithColor(ctx, c.CGColor);
        CGContextAddArc(ctx, x, y, fillRadius, 0, M_PI * 2, clocklwise);
        CGContextStrokePath(ctx);
    }
}
like image 26
Oleg Shanyuk Avatar answered Nov 06 '22 13:11

Oleg Shanyuk


Use CAGradientLayer and mask it using CAShapeLayer Something like this

- (void)addCircle{
    CAShapeLayer *shapeLayer = [CAShapeLayer new];
    shapeLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(10, 10, 100, 100), 4, 4)].CGPath;
    shapeLayer.strokeColor = [UIColor redColor].CGColor;
    shapeLayer.contentsScale = [UIScreen mainScreen].scale;
    shapeLayer.shouldRasterize = NO;


    CAGradientLayer *_gradientLayer = [CAGradientLayer layer];
    _gradientLayer.frame =self.view.bounds;
    _gradientLayer.startPoint = CGPointMake(0.0, 1);
    _gradientLayer.endPoint = CGPointMake(1, 0);
    _gradientLayer.colors = @[(id)[UIColor blueColor].CGColor,(id)[UIColor redColor].CGColor];

    //Add gradient layer to view
    [self.view.layer addSublayer:_gradientLayer];
    _gradientLayer.mask = shapeLayer;
}

Above method will add a triangle may be you need to change start and end points. Also you can change gradient values to whatever you need.

Apple Docs

CAGradientLayer Tutorial

Update After update its more clear that its not triangle you want, but what you need is possible with CAGradientLayer and CAShapeLayer, you need to follow same approach where you can add gradient with different colors and locations (stops)(if you are adding locations then make sure locations and colors are equal) and then mask it with CAShapeLayer which was circle.

like image 162
Adnan Aftab Avatar answered Nov 06 '22 12:11

Adnan Aftab


Another take on Oleg's answer regarding the saturation (white gradient) that I find more pleasing, and in Swift (3).

You can add steps to the gradient if you want a bigger white circle (ex a 2nd white step at 0.2)

import UIKit

class HSView: UIView {
    override func draw(_ rect: CGRect) {
        let arcStep = 2 * CGFloat.pi / 360
        let isClockwise = false
        let x = rect.width / 2
        let y = rect.height / 2
        let radius = min(x, y) / 2
        let ctx = UIGraphicsGetCurrentContext()
        ctx?.setLineWidth(2 * radius)

        for i in 0..<360 {
            let color = UIColor(hue: CGFloat(i)/360, saturation: 1, brightness: 1, alpha: 1)
            let startAngle = CGFloat(i) * arcStep
            let endAngle = startAngle + arcStep + 0.02

            ctx?.setStrokeColor(color.cgColor)
            ctx?.addArc(center: CGPoint(x: x, y: y), radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: isClockwise)
            ctx?.strokePath()
        }

        let gradient = CGGradient(colorsSpace: UIColor.white.cgColor.colorSpace,
                                  colors: [
                                    UIColor.white.cgColor,
                                    UIColor.white.withAlphaComponent(0).cgColor,
                                    ] as CFArray,
                                  locations: [
                                    0,
                                    1,
            ]
        )
        ctx?.drawRadialGradient(gradient!, startCenter: CGPoint(x: x, y: y), startRadius: 0, endCenter: CGPoint(x: x, y: y), endRadius: 2 * radius, options: .drawsAfterEndLocation)
    }
}

Result

like image 2
Arnaud Avatar answered Nov 06 '22 13:11

Arnaud


You can try this:

    //// General Declarations
CGContextRef context = UIGraphicsGetCurrentContext();


//// Shadow Declarations
NSShadow* shadow = [[NSShadow alloc] init];
[shadow setShadowColor: UIColor.whiteColor];
[shadow setShadowOffset: CGSizeMake(2.1, -4.1)];
[shadow setShadowBlurRadius: 5];

//// Bezier Drawing
UIBezierPath* bezierPath = UIBezierPath.bezierPath;
[UIColor.blackColor setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];


//// Bezier 2 Drawing
UIBezierPath* bezier2Path = UIBezierPath.bezierPath;
[bezier2Path moveToPoint: CGPointMake(170.5, 59.5)];
[bezier2Path addCurveToPoint: CGPointMake(170.5, 71.5) controlPoint1: CGPointMake(173.5, 65.5) controlPoint2: CGPointMake(170.5, 71.5)];
[bezier2Path addLineToPoint: CGPointMake(155.5, 57.5)];
[bezier2Path addLineToPoint: CGPointMake(170.5, 59.5)];
[UIColor.redColor setFill];
[bezier2Path fill];

////// Bezier 2 Inner Shadow
CGContextSaveGState(context);
UIRectClip(bezier2Path.bounds);
CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL);

CGContextSetAlpha(context, CGColorGetAlpha([shadow.shadowColor CGColor]));
CGContextBeginTransparencyLayer(context, NULL);
{
    UIColor* opaqueShadow = [shadow.shadowColor colorWithAlphaComponent: 1];
    CGContextSetShadowWithColor(context, shadow.shadowOffset, shadow.shadowBlurRadius, [opaqueShadow CGColor]);
    CGContextSetBlendMode(context, kCGBlendModeSourceOut);
    CGContextBeginTransparencyLayer(context, NULL);

    [opaqueShadow setFill];
    [bezier2Path fill];

    CGContextEndTransparencyLayer(context);
}
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);

and the result will be: enter image description here

like image 1
Teja Nandamuri Avatar answered Nov 06 '22 11:11

Teja Nandamuri