如何使用CAGradientLayer绘制渐变色轮? [英] How to draw a gradient color wheel using CAGradientLayer?

查看:210
本文介绍了如何使用CAGradientLayer绘制渐变色轮?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从这些链接中得到了一些参考 -






  • 现在,我的问题是如何获得这些颜色是渐变效果,以便每种颜色与渐变颜色层混合?

    解决方案

    一种方法是构建图像和手动操作像素缓冲区:




    • 创建具有特定大小和特定类型的 CGContext ;

    • 通过数据属性访问其数据缓冲区;

    • 将其重新绑定到成为它的地方容易操作该缓冲区(我使用 Pixel struct 用于像素的32位表示);

    • 逐个循环显示像素,将其转换为角度 radius 表示此图片中的圆圈;和

    • 如果它在圆圈内,则创建一个适当颜色的像素;如果没有,请将其设为零阿尔法像素。



    因此在Swift 3中:

      func buildHueCircle(在rect:CGRect,radius:CGFloat,scale:CGFloat = UIScreen.main.scale) - > UIImage的? {
    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 ..<高度{
    for x in 0 ..< width {
    let angle = fmod(atan2(CGFloat(x) - center.x,CGFloat(y) - center.y)+ 2 * .pi,2 * .pi)
    let distance = hypot (CGFloat(x) - center.x,CGFloat(y) - center.y)

    let value = UIColor(hue:angle / 2 / .pi,饱和度:1,亮度:1,alpha :1)

    var red:CGFloat = 0
    var green:CGFloat = 0
    var blue:CGFloat = 0
    var alpha:CGFloat = 0
    value.getRed(& red,green:& green,blue:& blue,alpha:& alpha)

    if distance< =(radius * scale){
    pixel = Pixel(红色:UInt8(红色* 255),
    绿色:UInt8(绿色* 255),
    蓝色:UInt8(蓝色* 255),
    alpha:UInt8(alpha * 255 ))
    } else {
    pixel = Pixel(红色:255,绿色:255,蓝色:255,alpha:0)
    }
    像素[y *宽度+ x] =像素
    }
    }

    让cgImage = context.makeImage()!
    返回UIImage(cgImage:cgImage,scale:scale,orientation:.up)
    }

    其中

      struct Pixel:Equatable {
    private var rgba:UInt32

    var red:UInt8 {
    返回UInt8((rgba>> 24)& 255)
    }

    var green:UInt8 {
    返回UInt8( (rgba>> 16)& 255)
    }

    var blue:UInt8 {
    返回UInt8((rgba>> 8)& 255)
    }

    var alpha:UInt8 {
    返回UInt8((rgba>> 0)& 255)
    }

    init (红色:UInt8,绿色:UInt8,蓝色:UInt8,alpha:UInt8){
    rgba =(UInt32(红色)<< 24)| (UInt32(绿色)<< 16)| (UInt32(蓝色)<< 8)| (UInt32(alpha)<< 0)
    }

    static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue

    static func ==(lhs:Pixel,rhs:Pixel) - > Bool {
    return lhs.rgba == rhs.rgba
    }
    }

    收益率:




    I got some reference from these links-

    I have gone through the concept of "HSV colour space". But I want to draw a color wheel using RGB with the help of CAGradientLayer.

    Here is the code snippet of making a color wheel by using simple RGB color array and UIBezierPath -

    func drawColorWheel()
    {
        context?.saveGState()
    
        range = CGFloat(100.00 / CGFloat(colorArray.count))
    
        for k in 0 ..< colorArray.count
        {
    
            drawSlice(startPercent: CGFloat(k) * range, endPercent: CGFloat(CGFloat(k + 1) * range), color: colorArray.object(at: k) as! UIColor)
        }
    
        context?.restoreGState()
    }
    
    func drawSlice(startPercent: CGFloat, endPercent: CGFloat, color: UIColor)
    {        
        let startAngle = getAngleAt(percentage: startPercent)
        let endAngle = getAngleAt(percentage: endPercent)
    
        let path =  getArcPath(startAngle: startAngle, endAngle: endAngle)
        color.setFill()
        path.fill()
    }
    

    Where getAngleAt() and getArcPath() are the private functions to draw the path with an angle.

    Here is the final output of my code -

    Now, my question is the how to give these colors a gradient effect so that each colors mix up with gradient color layer?

    解决方案

    One approach is to build an image and manipulate the pixel buffer manually:

    • Create CGContext of certain size and certain type;
    • Access its data buffer via data property;
    • Rebind that to something that makes it easy to manipulate that buffer (I use a Pixel, a struct for the 32-bit representation of a pixel);
    • Loop through the pixels, one by one, converting that to an angle and radius for the circle within this image; and
    • Create a pixel of the appropriate color if it's inside the circle; make it a zero-alpha pixel if not.

    So in Swift 3:

    func buildHueCircle(in rect: CGRect, radius: CGFloat, scale: CGFloat = UIScreen.main.scale) -> UIImage? {
        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 = fmod(atan2(CGFloat(x) - center.x, CGFloat(y) - center.y) + 2 * .pi, 2 * .pi)
                let distance = hypot(CGFloat(x) - center.x, CGFloat(y) - center.y)
    
                let value = UIColor(hue: angle / 2 / .pi, saturation: 1, brightness: 1, alpha: 1)
    
                var red: CGFloat = 0
                var green: CGFloat = 0
                var blue: CGFloat = 0
                var alpha: CGFloat = 0
                value.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
    
                if distance <= (radius * scale) {
                    pixel = Pixel(red:   UInt8(red * 255),
                                  green: UInt8(green * 255),
                                  blue:  UInt8(blue * 255),
                                  alpha: UInt8(alpha * 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)
    }
    

    Where

    struct Pixel: Equatable {
        private var rgba: UInt32
    
        var red: UInt8 {
            return UInt8((rgba >> 24) & 255)
        }
    
        var green: UInt8 {
            return UInt8((rgba >> 16) & 255)
        }
    
        var blue: UInt8 {
            return UInt8((rgba >> 8) & 255)
        }
    
        var alpha: UInt8 {
            return UInt8((rgba >> 0) & 255)
        }
    
        init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) {
            rgba = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0)
        }
    
        static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
    
        static func ==(lhs: Pixel, rhs: Pixel) -> Bool {
            return lhs.rgba == rhs.rgba
        }
    }
    

    That yields:

    Or you can tweak the brightness or saturation based upon the radius:

    这篇关于如何使用CAGradientLayer绘制渐变色轮?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆