Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/116.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带角梯度的iOS圆_Ios_View_Gradient_Geometry - Fatal编程技术网

带角梯度的iOS圆

带角梯度的iOS圆,ios,view,gradient,geometry,Ios,View,Gradient,Geometry,如何在iOS中以编程方式绘制这样的渐变 目前,我只找到了创建从圆心到圆边缘渐变的代码(除了整圆之外)。如果您想要这样的渐变,您可能需要自己实现它。例如,这将创建一个像素缓冲区数据提供程序,以该扫描径向模式填充alpha/红色/绿色/蓝色数据,并从中创建图像: - (UIImage *)buildAngularGradientInRect:(CGRect)rect radius:(CGFloat)radius

如何在iOS中以编程方式绘制这样的渐变


目前,我只找到了创建从圆心到圆边缘渐变的代码(除了整圆之外)。

如果您想要这样的渐变,您可能需要自己实现它。例如,这将创建一个像素缓冲区数据提供程序,以该扫描径向模式填充alpha/红色/绿色/蓝色数据,并从中创建图像:

- (UIImage *)buildAngularGradientInRect:(CGRect)rect
                                 radius:(CGFloat)radius
                             startAngle:(CGFloat)startAngle
                               endAngle:(CGFloat)endAngle
                             startColor:(UIColor *)startColor
                               endColor:(UIColor *)endColor
                              clockwise:(BOOL)clockwise
                                  scale:(CGFloat)scale
{
    if (scale == 0) scale = [[UIScreen mainScreen] scale];

    CGFloat startRed, startGreen, startBlue, startAlpha;
    [startColor getRed:&startRed green:&startGreen blue:&startBlue alpha:&startAlpha];

    CGFloat endRed, endGreen, endBlue, endAlpha;
    [endColor getRed:&endRed green:&endGreen blue:&endBlue alpha:&endAlpha];

    size_t width = rect.size.width * scale;
    size_t height = rect.size.height * scale;
    CGPoint center = CGPointMake(width / 2.0, height / 2.0);
    size_t bufferSize = width * height * 4;
    NSMutableData *data = [NSMutableData dataWithCapacity:bufferSize];
    struct {
        UInt8 alpha;
        UInt8 red;
        UInt8 green;
        UInt8 blue;
    } argb;

    size_t bitsPerComponent = 8;
    size_t bitsPerPixel = 4 * bitsPerComponent;
    size_t bytesPerRow = 4 * width;

    for (NSInteger y = 0; y < height; y++) {
        for (NSInteger x = 0; x < width; x++) {
            CGFloat angle = atan2(y - center.y, x - center.x);
            CGFloat distance = hypot(y - center.y, x - center.x);
            CGFloat value = [self percentAngle:angle betweenStart:startAngle end:endAngle clockwise:clockwise];
            if (distance <= (radius * scale) && value >= 0.0 && value <= 1.0) {
                argb.alpha = (startAlpha + (endAlpha - startAlpha) * value) * 255;
                argb.red   = (startRed   + (endRed   - startRed)   * value) * 255;
                argb.green = (startGreen + (endGreen - startGreen) * value) * 255;
                argb.blue  = (startBlue  + (endBlue  - startBlue)  * value) * 255;
            } else {
                argb.alpha = 0;
                argb.red   = 255;
                argb.green = 255;
                argb.blue  = 255;
            }
            [data appendBytes:&argb length:sizeof(argb)];
        }
    }

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
    CGImageRef imageRef = CGImageCreate(width,
                                        height,
                                        bitsPerComponent,
                                        bitsPerPixel,
                                        bytesPerRow,
                                        colorSpace,
                                        (CGBitmapInfo)kCGImageAlphaPremultipliedFirst,
                                        provider,
                                        NULL,
                                        NO,
                                        kCGRenderingIntentDefault);

    CGColorSpaceRelease(colorSpace);
    CGDataProviderRelease(provider);
    UIImage *image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
    CGImageRelease(imageRef);

    return image;
}

- (CGFloat)percentAngle:(CGFloat)angle betweenStart:(CGFloat)start end:(CGFloat)end clockwise:(BOOL)clockwise
{
    while (start < 0) start += M_PI * 2.0;
    while (angle < 0) angle += M_PI * 2.0;
    while (end < 0)   end += M_PI * 2.0;
    if (clockwise) {
        while (end < start) end += M_PI * 2.0;
        while (angle < start) angle += M_PI * 2.0;
    } else {
        while (start < end) end -= M_PI * 2.0;
        while (start < angle) angle -= M_PI * 2.0;
    }
    CGFloat range = end - start;
    CGFloat value = angle - start;

    return value / range;
}
或者,如您的示例中所示,创建一个使用alpha通道的渐变,然后将其作为遮罩应用于另一个视图:

UIImage *image = [self buildAngularGradientInRect:view.bounds
                                           radius:view.bounds.size.width / 2.0
                                       startAngle:M_PI + M_PI_4
                                         endAngle:M_PI + M_PI_2 + M_PI_4
                                       startColor:[UIColor clearColor]
                                         endColor:[UIColor whiteColor]
                                        clockwise:YES
                                            scale:0];

CALayer *maskLayer = [CALayer layer];
maskLayer.frame = view.bounds;
maskLayer.contents = (id)image.CGImage;
view.layer.mask = maskLayer;
希望这说明了可以应用于图像或遮罩的像素级控制


FWIW,这里是一个Swift 3格式副本:

func buildAngularGradient(in rect: CGRect, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, startColor: UIColor, endColor: UIColor, clockwise: Bool = true, scale: CGFloat = UIScreen.main.scale) -> UIImage? {
    var startRed: CGFloat = 0
    var startGreen: CGFloat = 0
    var startBlue: CGFloat = 0
    var startAlpha: CGFloat = 0
    startColor.getRed(&startRed, green: &startGreen, blue: &startBlue, alpha: &startAlpha)

    var endRed: CGFloat = 0
    var endGreen: CGFloat = 0
    var endBlue: CGFloat = 0
    var endAlpha: CGFloat = 0
    endColor.getRed(&endRed, green: &endGreen, blue: &endBlue, alpha: &endAlpha)

    let width = Int(rect.size.width * scale)
    let height = Int(rect.size.height * scale)
    let center = CGPoint(x: width / 2, y: height / 2)

    let space = CGColorSpaceCreateDeviceRGB()
    let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: width * 4, space: space, bitmapInfo: Pixel.bitmapInfo)!

    let buffer = context.data!

    let pixels = buffer.bindMemory(to: Pixel.self, capacity: width * height)
    var pixel: Pixel
    for y in 0 ..< height {
        for x in 0 ..< width {
            let angle = atan2(CGFloat(y) - center.y, CGFloat(x) - center.x)
            let distance = hypot(CGFloat(y) - center.y, CGFloat(x) - center.x)

            let value = percent(angle: angle, between: startAngle, and: endAngle, clockwise: true)

            //    CGFloat value = [self percentAngle:angle betweenStart:startAngle end:endAngle clockwise:clockwise];
            if distance <= (radius * scale) && value >= 0.0 && value <= 1.0 {
                pixel = Pixel(red:   UInt8((startRed   + (endRed   - startRed)   * value) * 255),
                              green: UInt8((startGreen + (endGreen - startGreen) * value) * 255),
                              blue:  UInt8((startBlue  + (endBlue  - startBlue)  * value) * 255),
                              alpha: UInt8((startAlpha + (endAlpha - startAlpha) * value) * 255))
            } else {
                pixel = Pixel(red: 255, green: 255, blue: 255, alpha: 0)
            }
            pixels[y * width + x] = pixel
        }
    }

    let cgImage = context.makeImage()!
    return UIImage(cgImage: cgImage, scale: scale, orientation: .up)
}

private func percent(angle: CGFloat, between start: CGFloat, and end: CGFloat, clockwise: Bool) -> CGFloat {
    var start = start

    while start < 0 { start += .pi * 2 }

    var angle = angle
    while angle < 0 { angle += .pi * 2 }

    var end = end
    while end < 0 { end += .pi * 2 }

    if clockwise {
        while (end < start) { end += .pi * 2 }
        while (angle < start) { angle += .pi * 2 }
    } else {
        while (start < end) { end -= .pi * 2 }
        while (start < angle) { angle -= .pi * 2 }
    }
    let range = end - start
    let value = angle - start

    return value / range;
}
func buildAngularGradient(在rect:CGRect中,半径:CGFloat,startAngle:CGFloat,endAngle:CGFloat,startColor:UIColor,endColor:UIColor,顺时针:Bool=true,scale:CGFloat=UIScreen.main.scale)->UIImage?{
var startRed:CGFloat=0
var startGreen:CGFloat=0
var startBlue:CGFloat=0
var startAlpha:CGFloat=0
startColor.getRed(&startRed,绿色:&startGreen,蓝色:&startBlue,alpha:&startAlpha)
变量endRed:CGFloat=0
变量endGreen:CGFloat=0
var endBlue:CGFloat=0
var endAlpha:CGFloat=0
getRed(&endRed,green:&endGreen,blue:&endBlue,alpha:&endAlpha)
let width=Int(rect.size.width*scale)
let height=Int(rect.size.height*scale)
设中心=CGPoint(x:宽度/2,y:高度/2)
let space=CGColorSpaceCreateDeviceRGB()
让context=CGContext(数据:nil,宽度:宽度,高度:高度,bitsPerComponent:8,bytesPerRow:width*4,空格:空格,bitmapInfo:Pixel.bitmapInfo)!
让buffer=context.data!
让像素=缓冲区.bindMemory(to:Pixel.self,容量:宽度*高度)
像素:像素
对于y,0..<高度{
对于0中的x..<宽度{
让角度=atan2(CGFloat(y)-中心.y,CGFloat(x)-中心.x)
让距离=hypot(CGFloat(y)-center.y,CGFloat(x)-center.x)
let值=百分比(角度:角度,介于:startAngle和:endAngle之间,顺时针:true)
//CGFloat值=[自身百分比角度:开始之间的角度:起始端:结束角顺时针:顺时针];
如果距离=0.0&&值CGFloat{
var start=start
而start<0{start+=.pi*2}
变量角度=角度
而角度<0{angle+=.pi*2}
var end=结束
而end<0{end+=.pi*2}
如果顺时针{
而(end
在哪里

struct Pixel:equalable{
专用变量rgba:UInt32
红色变量:UInt8{
返回UInt8((rgba>>24)和255)
}
绿色变量:UInt8{
返回UInt8((rgba>>16)和255)
}
蓝色变种:UInt8{
返回UInt8((rgba>>8)和255)
}
阿尔法变量:UInt8{
返回UInt8((rgba>>0)和255)
}
初始值(红色:UInt8,绿色:UInt8,蓝色:UInt8,阿尔法:UInt8){

rgba=(UInt32(红色)如果您想要这样的渐变,您可能需要自己实现。例如,这将创建一个像素缓冲区数据提供程序,以这种扫描径向模式填充alpha/red/green/blue数据,并从中创建图像:

- (UIImage *)buildAngularGradientInRect:(CGRect)rect
                                 radius:(CGFloat)radius
                             startAngle:(CGFloat)startAngle
                               endAngle:(CGFloat)endAngle
                             startColor:(UIColor *)startColor
                               endColor:(UIColor *)endColor
                              clockwise:(BOOL)clockwise
                                  scale:(CGFloat)scale
{
    if (scale == 0) scale = [[UIScreen mainScreen] scale];

    CGFloat startRed, startGreen, startBlue, startAlpha;
    [startColor getRed:&startRed green:&startGreen blue:&startBlue alpha:&startAlpha];

    CGFloat endRed, endGreen, endBlue, endAlpha;
    [endColor getRed:&endRed green:&endGreen blue:&endBlue alpha:&endAlpha];

    size_t width = rect.size.width * scale;
    size_t height = rect.size.height * scale;
    CGPoint center = CGPointMake(width / 2.0, height / 2.0);
    size_t bufferSize = width * height * 4;
    NSMutableData *data = [NSMutableData dataWithCapacity:bufferSize];
    struct {
        UInt8 alpha;
        UInt8 red;
        UInt8 green;
        UInt8 blue;
    } argb;

    size_t bitsPerComponent = 8;
    size_t bitsPerPixel = 4 * bitsPerComponent;
    size_t bytesPerRow = 4 * width;

    for (NSInteger y = 0; y < height; y++) {
        for (NSInteger x = 0; x < width; x++) {
            CGFloat angle = atan2(y - center.y, x - center.x);
            CGFloat distance = hypot(y - center.y, x - center.x);
            CGFloat value = [self percentAngle:angle betweenStart:startAngle end:endAngle clockwise:clockwise];
            if (distance <= (radius * scale) && value >= 0.0 && value <= 1.0) {
                argb.alpha = (startAlpha + (endAlpha - startAlpha) * value) * 255;
                argb.red   = (startRed   + (endRed   - startRed)   * value) * 255;
                argb.green = (startGreen + (endGreen - startGreen) * value) * 255;
                argb.blue  = (startBlue  + (endBlue  - startBlue)  * value) * 255;
            } else {
                argb.alpha = 0;
                argb.red   = 255;
                argb.green = 255;
                argb.blue  = 255;
            }
            [data appendBytes:&argb length:sizeof(argb)];
        }
    }

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
    CGImageRef imageRef = CGImageCreate(width,
                                        height,
                                        bitsPerComponent,
                                        bitsPerPixel,
                                        bytesPerRow,
                                        colorSpace,
                                        (CGBitmapInfo)kCGImageAlphaPremultipliedFirst,
                                        provider,
                                        NULL,
                                        NO,
                                        kCGRenderingIntentDefault);

    CGColorSpaceRelease(colorSpace);
    CGDataProviderRelease(provider);
    UIImage *image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
    CGImageRelease(imageRef);

    return image;
}

- (CGFloat)percentAngle:(CGFloat)angle betweenStart:(CGFloat)start end:(CGFloat)end clockwise:(BOOL)clockwise
{
    while (start < 0) start += M_PI * 2.0;
    while (angle < 0) angle += M_PI * 2.0;
    while (end < 0)   end += M_PI * 2.0;
    if (clockwise) {
        while (end < start) end += M_PI * 2.0;
        while (angle < start) angle += M_PI * 2.0;
    } else {
        while (start < end) end -= M_PI * 2.0;
        while (start < angle) angle -= M_PI * 2.0;
    }
    CGFloat range = end - start;
    CGFloat value = angle - start;

    return value / range;
}
或者,如您的示例中所示,创建一个使用alpha通道的渐变,然后将其作为遮罩应用于另一个视图:

UIImage *image = [self buildAngularGradientInRect:view.bounds
                                           radius:view.bounds.size.width / 2.0
                                       startAngle:M_PI + M_PI_4
                                         endAngle:M_PI + M_PI_2 + M_PI_4
                                       startColor:[UIColor clearColor]
                                         endColor:[UIColor whiteColor]
                                        clockwise:YES
                                            scale:0];

CALayer *maskLayer = [CALayer layer];
maskLayer.frame = view.bounds;
maskLayer.contents = (id)image.CGImage;
view.layer.mask = maskLayer;
希望这说明了可以应用于图像或遮罩的像素级控制


FWIW,这里是一个Swift 3格式副本:

func buildAngularGradient(in rect: CGRect, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, startColor: UIColor, endColor: UIColor, clockwise: Bool = true, scale: CGFloat = UIScreen.main.scale) -> UIImage? {
    var startRed: CGFloat = 0
    var startGreen: CGFloat = 0
    var startBlue: CGFloat = 0
    var startAlpha: CGFloat = 0
    startColor.getRed(&startRed, green: &startGreen, blue: &startBlue, alpha: &startAlpha)

    var endRed: CGFloat = 0
    var endGreen: CGFloat = 0
    var endBlue: CGFloat = 0
    var endAlpha: CGFloat = 0
    endColor.getRed(&endRed, green: &endGreen, blue: &endBlue, alpha: &endAlpha)

    let width = Int(rect.size.width * scale)
    let height = Int(rect.size.height * scale)
    let center = CGPoint(x: width / 2, y: height / 2)

    let space = CGColorSpaceCreateDeviceRGB()
    let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: width * 4, space: space, bitmapInfo: Pixel.bitmapInfo)!

    let buffer = context.data!

    let pixels = buffer.bindMemory(to: Pixel.self, capacity: width * height)
    var pixel: Pixel
    for y in 0 ..< height {
        for x in 0 ..< width {
            let angle = atan2(CGFloat(y) - center.y, CGFloat(x) - center.x)
            let distance = hypot(CGFloat(y) - center.y, CGFloat(x) - center.x)

            let value = percent(angle: angle, between: startAngle, and: endAngle, clockwise: true)

            //    CGFloat value = [self percentAngle:angle betweenStart:startAngle end:endAngle clockwise:clockwise];
            if distance <= (radius * scale) && value >= 0.0 && value <= 1.0 {
                pixel = Pixel(red:   UInt8((startRed   + (endRed   - startRed)   * value) * 255),
                              green: UInt8((startGreen + (endGreen - startGreen) * value) * 255),
                              blue:  UInt8((startBlue  + (endBlue  - startBlue)  * value) * 255),
                              alpha: UInt8((startAlpha + (endAlpha - startAlpha) * value) * 255))
            } else {
                pixel = Pixel(red: 255, green: 255, blue: 255, alpha: 0)
            }
            pixels[y * width + x] = pixel
        }
    }

    let cgImage = context.makeImage()!
    return UIImage(cgImage: cgImage, scale: scale, orientation: .up)
}

private func percent(angle: CGFloat, between start: CGFloat, and end: CGFloat, clockwise: Bool) -> CGFloat {
    var start = start

    while start < 0 { start += .pi * 2 }

    var angle = angle
    while angle < 0 { angle += .pi * 2 }

    var end = end
    while end < 0 { end += .pi * 2 }

    if clockwise {
        while (end < start) { end += .pi * 2 }
        while (angle < start) { angle += .pi * 2 }
    } else {
        while (start < end) { end -= .pi * 2 }
        while (start < angle) { angle -= .pi * 2 }
    }
    let range = end - start
    let value = angle - start

    return value / range;
}
func buildAngularGradient(在rect:CGRect中,半径:CGFloat,startAngle:CGFloat,endAngle:CGFloat,startColor:UIColor,endColor:UIColor,顺时针:Bool=true,scale:CGFloat=UIScreen.main.scale)->UIImage{
var startRed:CGFloat=0
var startGreen:CGFloat=0
var startBlue:CGFloat=0
var startAlpha:CGFloat=0
startColor.getRed(&startRed,绿色:&startGreen,蓝色:&startBlue,alpha:&startAlpha)
变量endRed:CGFloat=0
变量endGreen:CGFloat=0
var endBlue:CGFloat=0
var endAlpha:CGFloat=0
getRed(&endRed,green:&endGreen,blue:&endBlue,alpha:&endAlpha)
let width=Int(rect.size.width*scale)
let height=Int(rect.size.height*scale)
设中心=CGPoint(x:宽度/2,y:高度/2)
let space=CGColorSpaceCreateDeviceRGB()
让context=CGContext(数据:nil,宽度:宽度,高度:高度,bitsPerComponent:8,bytesPerRow:width*4,空格:空格,bitmapInfo:Pixel.bitmapInfo)!
让buffer=context.data!
让像素=缓冲区.bindMemory(to:Pixel.self,容量:宽度*高度)
像素:像素
对于y,0..<高度{
对于0中的x..<宽度{
让角度=atan2(CGFloat(y)-中心.y,CGFloat(x)-中心.x)
让距离=hypot(CGFloat(y)-center.y,CGFloat(x)-center.x)
let值=百分比(角度:角度,介于:startAngle和:endAngle之间,顺时针:true)
//CGFloat值=[自身百分比角度:开始之间的角度:起始端:结束角顺时针:顺时针];
如果距离=0.0&&值CGFloat{
var start=start
而start<0{start+=.pi*2}
变量角度=角度
而角度<0{angle+=.pi*2}
var end=结束
而end<0{end+=.pi*2}
如果顺时针{
而(end
在哪里

struct Pixel:equalable{
私人v