UIBezierPath with color gradient

前端 未结 5 1654
孤街浪徒
孤街浪徒 2021-02-08 15:21

I\'ve got an question about UIBezierPath.

For example I\'ve got this path:

\"\"

Now I want to have

相关标签:
5条回答
  • 2021-02-08 15:36

    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.

    0 讨论(0)
  • 2021-02-08 15:41

    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:

    0 讨论(0)
  • 2021-02-08 15:46

    You will archive it by using QuartsCore. If you want get image with your figure, you can call UIGraphicsBeginImageContext(), if you want draw it on UIView you should overload method - (void)drawRect:(CGRect)rect of UIView. You can add path to context, and use it for clipping context (Don't forget save the context state before). After you can draw the gradient. The gradient will be clipped by path.

    You will get something like this:

    CGPathRef path = [bezierPath CGPath];
    CGContextSaveGState(context);
    
    CGContextAddPath(context, path);
    CGContextClip(context);
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    NSArray *colors = [NSArray arrayWithObjects:(id)[UIColor redColor].CGColor, (id)[UIColor blueColor].CGColor, nil];
    CGGradientRef gradient = CGGradientCreateWithColors( colorSpace, (CFArrayRef)colors, NULL);
    CGColorSpaceRelease(colorSpace);
    colorSpace = NULL;
    
    CGContextDrawLinearGradient(context, gradient, CGPointMake(0.0, 0.0), CGPointMake(100.0, 100.0), kNilOptions);
    
    CGContextRestoreGState(context);
    
    0 讨论(0)
  • 2021-02-08 15:50

    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)
        }
    }
    

    0 讨论(0)
  • 2021-02-08 15:52

    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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题