如何使用CAGradientLayer绘制渐变色轮? [英] How to draw a gradient color wheel using 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()
andgetArcPath()
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
, astruct
for the 32-bit representation of a pixel); - Loop through the pixels, one by one, converting that to an
angle
andradius
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屋!
- 创建具有特定大小和特定类型的