Several methods for ios to achieve color gradient

Demo address: https://github.com/xiaochaofeiyu/YSCAnimation If
useful, please ask a star, welcome to suggest and discuss.

1. CAGradientLayer realizes gradient

CAGradientLayer is a special subclass of CALayer. It is used to generate color gradient layers. It is more convenient to use. The following describes its related properties:

  1. colors gradient colors

  2. locations The division point of the gradient color

  3. startPoint&endPoint The direction of the color gradient, the range is between (0,0) and (1.0,1.0), such as (0,0)(1.0,0) represents the horizontal gradient, (0,0)(0,1.0) represents the vertical Straight gradient

    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.colors = @[(__bridge id)[UIColor redColor].CGColor, (__bridge id)[UIColor yellowColor].CGColor, (__bridge id)[UIColor blueColor].CGColor];
    gradientLayer.locations = @[@0.3, @0.5, @1.0];
    gradientLayer.startPoint = CGPointMake(0, 0);
    gradientLayer.endPoint = CGPointMake(1.0, 0);
    gradientLayer.frame = CGRectMake(0, 100, 300, 100);
    [self.view.layer addSublayer:gradientLayer];

1611446-245980be4c47c9d9.png

CAGradientLayer is simple and intuitive to realize the gradient between the gradients, but there are certain limitations, such as the inability to customize the shape of the entire gradient area, such as circular and curved gradients.

2. Core Graphics related methods to achieve gradient

There are two methods for drawing gradient colors in iOS Core Graphics. CGContextDrawLinearGradient can be used to generate linear gradients, and CGContextDrawRadialGradient is used to generate color gradients in the direction of the circle radius. The function can customize the path, no matter what shape it is, the principle is to make a Clip, so you need to call the CGContextAddPath function before the CGContextClip function to add the CGPathRef to the Context.
Another thing to pay attention to is the direction of the gradient. The direction is controlled by two points. The unit of the point is the coordinate. Therefore, it is necessary to correctly find the correct point from CGPathRef. Of course, there are many ways to see the specific implementation. In this example, I simply return the rectangular area of ​​CGPathRef by calling the CGPathGetBoundingBox function, and then take two points based on this rectangle. The reader can Modify the specific code according to your own needs.

1-> Linear gradient

- (void)drawLinearGradient:(CGContextRef)context
                      path:(CGPathRef)path
                startColor:(CGColorRef)startColor
                  endColor:(CGColorRef)endColor
{
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGFloat locations[] = { 0.0, 1.0 };

    NSArray *colors = @[(__bridge id) startColor, (__bridge id) endColor];

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations);


    CGRect pathRect = CGPathGetBoundingBox(path);

    //The specific direction can be modified according to needs
    CGPoint startPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMidY(pathRect));
    CGPoint endPoint = CGPointMake(CGRectGetMaxX(pathRect), CGRectGetMidY(pathRect));

    CGContextSaveGState(context);
    CGContextAddPath(context, path);
    CGContextClip(context);
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
    CGContextRestoreGState(context);

    CGGradientRelease(gradient);
    CGColorSpaceRelease(colorSpace);
}

- (void)viewDidLoad 
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    //Create CGContextRef
    UIGraphicsBeginImageContext(self.view.bounds.size);
    CGContextRef gc = UIGraphicsGetCurrentContext();

    //Create CGMutablePathRef
    CGMutablePathRef path = CGPathCreateMutable();

    //Draw Path
    CGRect rect = CGRectMake (0, 100, 300, 200);
    CGPathMoveToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGPathAddLineToPoint(path, NULL, CGRectGetMidX(rect), CGRectGetMaxY(rect));
    CGPathAddLineToPoint(path, NULL, CGRectGetWidth(rect), CGRectGetMaxY(rect));
    CGPathCloseSubpath(path);

    //Draw a gradient
    [self drawLinearGradient:gc path:path startColor:[UIColor greenColor].CGColor endColor:[UIColor redColor].CGColor];

    //Pay attention to release CGMutablePathRef
    CGPathRelease(path);

    //Get the image from the Context and display it on the interface
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
    [self.view addSubview:imgView];
}

1611446-35c93df45fdf526b.png

2-> Gradient in the radius of the circle

- (void)drawRadialGradient:(CGContextRef)context
                      path:(CGPathRef)path
                startColor:(CGColorRef)startColor
                  endColor:(CGColorRef)endColor
{
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGFloat locations[] = { 0.0, 1.0 };

    NSArray *colors = @[(__bridge id) startColor, (__bridge id) endColor];

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations);


    CGRect pathRect = CGPathGetBoundingBox(path);
    CGPoint center = CGPointMake(CGRectGetMidX(pathRect), CGRectGetMidY(pathRect));
    CGFloat radius = MAX(pathRect.size.width / 2.0, pathRect.size.height / 2.0) * sqrt(2);

    CGContextSaveGState(context);
    CGContextAddPath(context, path);
    CGContextEOClip(context);

    CGContextDrawRadialGradient(context, gradient, center, 0, center, radius, 0);

    CGContextRestoreGState(context);

    CGGradientRelease(gradient);
    CGColorSpaceRelease(colorSpace);
}

- (void)viewDidLoad 
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    //Create CGContextRef
    UIGraphicsBeginImageContext(self.view.bounds.size);
    CGContextRef gc = UIGraphicsGetCurrentContext();

    //Create CGMutablePathRef
    CGMutablePathRef path = CGPathCreateMutable();

    //Draw Path
    CGRect rect = CGRectMake (0, 100, 300, 200);
    CGPathMoveToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGPathAddLineToPoint(path, NULL, CGRectGetMidX(rect), CGRectGetMaxY(rect));
    CGPathAddLineToPoint(path, NULL, CGRectGetWidth(rect), CGRectGetMaxY(rect));
    CGPathAddLineToPoint(path, NULL, CGRectGetWidth(rect), CGRectGetMinY(rect));
    CGPathCloseSubpath(path);

    //Draw a gradient
    [self drawRadialGradient:gc path:path startColor:[UIColor greenColor].CGColor endColor:[UIColor redColor].CGColor];

    //Pay attention to release CGMutablePathRef
    CGPathRelease(path);

    //Get the image from the Context and display it on the interface
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
    [self.view addSubview:imgView];
}

1611446-dca1e1f9077947f9.png

3. Use CAShapeLayer as the layer's mask attribute

The mask property of CALayer can be used as a mask for the layer to display the (non-transparent) part of the mask; CAShapeLayer is a subclass of CALayer, and different shapes can be generated through the path property. If the CAShapeLayer object is used as the mask property of the layer, you can Generate layers of different shapes. Therefore, there are several steps to generate a color gradient:

  1. Generate an imageView (also can be a layer), the image attribute is a color gradient image

  2. Generate a CAShapeLayer object, specify the desired shape according to the path attribute

  3. Assign the CAShapeLayer object to the mask attribute of imageView

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.view addSubview:self.firstCircle];
    _firstCircle.frame = CGRectMake(0, 0, 200, 200);
    _firstCircle.center = CGPointMake(CGRectGetWidth(self.view.bounds) / 2.0, CGRectGetHeight(self.view.bounds) / 2.0);
    CGFloat firsCircleWidth = 5;
    self.firstCircleShapeLayer = [self generateShapeLayerWithLineWidth:firsCircleWidth];
    _firstCircleShapeLayer.path = [self generateBezierPathWithCenter:CGPointMake(100, 100) radius:100].CGPath;
    _firstCircle.layer.mask = _firstCircleShapeLayer;

- (CAShapeLayer *)generateShapeLayerWithLineWidth:(CGFloat)lineWidth
{
    CAShapeLayer *waveline = [CAShapeLayer layer];
    waveline.lineCap = kCALineCapButt;
    waveline.lineJoin = kCALineJoinRound;
    waveline.strokeColor = [UIColor redColor].CGColor;
    waveline.fillColor = [[UIColor clearColor] CGColor];
    waveline.lineWidth = lineWidth;
    waveline.backgroundColor = [UIColor clearColor].CGColor;

    return waveline;
}

- (UIBezierPath *)generateBezierPathWithCenter:(CGPoint)center radius:(CGFloat)radius
{
    UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:2*M_PI clockwise:NO];

    return circlePath;
}

- (UIImageView *)firstCircle
{
    if (!_firstCircle) {
        self.firstCircle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"circleBackground"]];
        _firstCircle.layer.masksToBounds = YES;
        _firstCircle.alpha = 1.0;
    }

    return _firstCircle;
}

1611446-9bbb8915d2d962dd.png

Demo address: https://github.com/xiaochaofeiyu/YSCAnimation
in YSCNewVoiceWaveView and YSCVoiceLoadingCircleView

Guess you like

Origin blog.csdn.net/wu347771769/article/details/55213350