英文:
Swift CAGradientLayer showing inaccurate color
问题
我正在使用CAGradientLayer为我的UIView添加渐变效果。我将渐变设置为红色,并进行了颜色测试,但当我检查显示的颜色时,它显示的RGB值与我指定的不同。有没有办法确保渐变显示我设置的颜色。
let gradientLayer2 = CAGradientLayer()
gradientLayer2.frame.size = colourPickerView.frame.size
gradientLayer2.colors = [
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor,
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor
]
gradientLayer2.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer2.endPoint = CGPoint(x: 1, y: 0)
gradientLayer2.cornerRadius = 20
colourPickerView.layer.insertSublayer(gradientLayer2, at: 0)
这显示红色的颜色为:<CGColor 0x283c8e400> [<CGColorSpace 0x283c989c0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)] ( 1 0.14902 0 1 )
(请注意,它显示绿色值为'0.14902')
当我为图层添加纯色背景而不是渐变时,它确实显示了正确的RGB值。
let layer = CALayer()
layer.frame.size = colourPickerView.frame.size
layer.backgroundColor = UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor
colourPickerView.layer.insertSublayer(layer, at: 0)
以下是我用来获取特定像素颜色的代码:
extension UIView {
func colorOfPointView(point: CGPoint) -> UIColor {
let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
var pixelData: [UInt8] = [0, 0, 0, 0]
let context = CGContext(data: &pixelData, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
context!.translateBy(x: -point.x, y: -point.y)
self.layer.render(in: context!)
let red: CGFloat = CGFloat(pixelData[0]) / CGFloat(255.0)
let green: CGFloat = CGFloat(pixelData[1]) / CGFloat(255.0)
let blue: CGFloat = CGFloat(pixelData[2]) / CGFloat(255.0)
let alpha: CGFloat = CGFloat(pixelData[3]) / CGFloat(255.0)
let color: UIColor = UIColor(red: red, green: green, blue: blue, alpha: alpha)
return color
}
}
英文:
I am using CAGradientLayer to add a gradient to my UIView. I am setting the gradient ad a solid red colourful testing, and when I check the color that is being displayed, it is showing different RGB values to those I have specified. Is there a way that I can make sure the gradient is showing the colours that I set.
let gradientLayer2 = CAGradientLayer()
gradientLayer2.frame.size = colourPickerView.frame.size
gradientLayer2.colors = [
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor,
]
gradientLayer2.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer2.endPoint = CGPoint(x: 1, y: 0)
gradientLayer2.cornerRadius = 20
colourPickerView.layer.insertSublayer(gradientLayer2, at: 0)
This shows the red color as: <CGColor 0x283c8e400> [<CGColorSpace 0x283c989c0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)] ( 1 0.14902 0 1 )
(Please note, it is showing the green value as '0.14902')
When I add a solid background colour to the layer, instead of a gradient, it does show the correct RGB values.
let layer = CALayer()
layer.frame.size = colourPickerView.frame.size
layer.backgroundColor = UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor
colourPickerView.layer.insertSublayer(layer, at: 0)
Here is the code that I am using to get the colour of a certain pixel:
extension UIView {
func colorOfPointView(point: CGPoint) -> UIColor {
let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
var pixelData: [UInt8] = [0, 0, 0, 0]
let context = CGContext(data: &pixelData, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
context!.translateBy(x: -point.x, y: -point.y)
self.layer.render(in: context!)
let red: CGFloat = CGFloat(pixelData[0]) / CGFloat(255.0)
let green: CGFloat = CGFloat(pixelData[1]) / CGFloat(255.0)
let blue: CGFloat = CGFloat(pixelData[2]) / CGFloat(255.0)
let alpha: CGFloat = CGFloat(pixelData[3]) / CGFloat(255.0)
let color: UIColor = UIColor(red: red, green: green, blue: blue, alpha: alpha)
return color
}
答案1
得分: 1
你遇到的问题是RGBA
与Display P3
或Extended sRGBA
之间的差异。
使用CGContext
和CAGradientLayer
的方法,例如,我们会得到Display P3
的值。
要获取“传统”的每组分量8位的值,我们可以首先将视图呈现为UIImage
,然后从图像中的某一点获取RGBA值。
使用以下两个扩展:
extension UIView {
func colorAt(point: CGPoint) -> UIColor? {
return renderView().getPixelColor(point: point)
}
func renderView() -> UIImage {
let renderer = UIGraphicsImageRenderer(size: bounds.size)
let image = renderer.image { rendererContext in
drawHierarchy(in: bounds, afterScreenUpdates: true)
}
return image
}
}
extension UIImage {
// 来自:https://stackoverflow.com/a/34596653/6257435
func getPixelColor(point: CGPoint) -> UIColor? {
guard let cgImage = cgImage else { return nil }
if point.x < 0 || point.x > size.width || point.y < 0 || point.y > size.height {
return nil
}
let width = Int(size.width)
let height = Int(size.height)
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let context = CGContext(data: nil,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: width * 4,
space: colorSpace,
bitmapInfo: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
else {
return nil
}
context.draw(cgImage, in: CGRect(origin: .zero, size: size))
guard let pixelBuffer = context.data else { return nil }
let pointer = pixelBuffer.bindMemory(to: UInt32.self, capacity: width * height)
let pixel = pointer[Int(point.y) * width + Int(point.x)]
let r: CGFloat = CGFloat(red(for: pixel)) / 255
let g: CGFloat = CGFloat(green(for: pixel)) / 255
let b: CGFloat = CGFloat(blue(for: pixel)) / 255
let a: CGFloat = CGFloat(alpha(for: pixel)) / 255
return UIColor(red: r, green: g, blue: b, alpha: a)
}
private func alpha(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 24) & 255)
}
private func red(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 16) & 255)
}
private func green(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 8) & 255)
}
private func blue(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 0) & 255)
}
private func rgba(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) -> UInt32 {
return (UInt32(alpha) << 24) | (UInt32(red) << 16) | (UInt32(green) << 8) | (UInt32(blue) << 0)
}
}
我们可以调用:
let theColor = someView.colorAt(point: CGPoint(x: 10, y: 10))
然后我们将得到我们期望的结果。
由于需要“以UIImage
形式捕获”,我们不希望反复调用它 - 例如,如果我们沿着渐变拖动以获取当前颜色... 如果可能的话,我们希望将视图呈现为UIImage
一次,然后重复调用preRenderedImage.getPixelColor(point: pt)
。
以下是一个快速示例...
运行时将如下所示:
我们有2个CAGradientLayer
视图... 第一个使用Red -> secondColor
,第二个使用secondColor -> secondColor
(因此它看起来是实心的)。
第三个视图有一个“左半部分”CALayer
和一个“右半部分”CALayer
,第四个视图是一个普通的UIView
,其.backgroundColor
设置为color2
。
按钮会循环显示红色、绿色、蓝色、黄色作为第二个颜色。
当我们触摸/拖动虚线时,我们将获得相同x坐标上每个视图的RGBA值(在中心y处),并在按钮下方的标签中显示结果。
使用上述扩展与以下代码...
View Controller
// 请参考原始文本,代码太长,无法一次性翻译完毕。
UIView子类
// 请参考原始文本,代码太长,无法一次性翻译完毕。
<details>
<summary>英文:</summary>
The issue you are running into is the difference between `RGBA` and `Display P3` or `Extended sRGBA`.
Using your approach with `CGContext` and a `CAGradientLayer`, for example, we get back the Display P3 values.
To get the "traditional" 8-bits-per-component values, we can first render the view to a `UIImage` and then get the RGBA values from a point in the image.
Using these two extensions:
extension UIView {
func colorAt(point: CGPoint) -> UIColor? {
return renderView().getPixelColor(point: point)
}
func renderView() -> UIImage {
let renderer = UIGraphicsImageRenderer(size: bounds.size)
let image = renderer.image { rendererContext in
drawHierarchy(in: bounds, afterScreenUpdates: true)
}
return image
}
}
extension UIImage {
// from: https://stackoverflow.com/a/34596653/6257435
func getPixelColor(point: CGPoint) -> UIColor? {
guard let cgImage = cgImage else { return nil }
if point.x < 0 || point.x > size.width || point.y < 0 || point.y > size.height {
return nil
}
let width = Int(size.width)
let height = Int(size.height)
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let context = CGContext(data: nil,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: width * 4,
space: colorSpace,
bitmapInfo: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
else {
return nil
}
context.draw(cgImage, in: CGRect(origin: .zero, size: size))
guard let pixelBuffer = context.data else { return nil }
let pointer = pixelBuffer.bindMemory(to: UInt32.self, capacity: width * height)
let pixel = pointer[Int(point.y) * width + Int(point.x)]
let r: CGFloat = CGFloat(red(for: pixel)) / 255
let g: CGFloat = CGFloat(green(for: pixel)) / 255
let b: CGFloat = CGFloat(blue(for: pixel)) / 255
let a: CGFloat = CGFloat(alpha(for: pixel)) / 255
return UIColor(red: r, green: g, blue: b, alpha: a)
}
private func alpha(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 24) & 255)
}
private func red(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 16) & 255)
}
private func green(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 8) & 255)
}
private func blue(for pixelData: UInt32) -> UInt8 {
return UInt8((pixelData >> 0) & 255)
}
private func rgba(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) -> UInt32 {
return (UInt32(alpha) << 24) | (UInt32(red) << 16) | (UInt32(green) << 8) | (UInt32(blue) << 0)
}
}
We can call:
let theColor = someView.colorAt(point: CGPoint(x: 10, y: 10))
and we'll get back what we were expecting.
Because of the need to "capture as `UIImage`" we don't want to be calling that over and over - such as if we're dragging along a gradient to get the current color... Instead, if possible, we'd want to render the view to a `UIImage` **once** and then repeatedly call `prerenderedImage.getPixelColor(point: pt)`.
Here's a quick example...
It will look like this when running:
[![enter image description here][1]][1] [![enter image description here][2]][2]
[![enter image description here][3]][3] [![enter image description here][4]][4]
We have 2 `CAGradientLayer` views... the first one using `Red -> secondColor` and the second one using `secondColor -> secondColor` (so it appear solid).
The 3rd view has a "left-half" `CALayer` and a "right-half" `CALayer` and the 4th view is a plain `UIView` with the `.backgroundColor` set.
The button cycles through Red, Green, Blue, Yellow as the second-colors.
When we touch / drag the dashed-line, we'll get the RGBA values from the same x-coordinate on each view (at center-y) and show the results in the label below the button.
Use the above extensions with this code...
**View Controller**
class ColorAtPointViewController: UIViewController {
// CAGradientLayer from color1 to color2
let gradientView1 = MyGradientView()
// CAGradientLayer from color2 to color2 (will appear solid)
let gradientView2 = MyGradientView()
// left-half CALayer color1 / right-half CALayer color2
let layerView = MyLayerView()
// plain UIView with .backgroundColor set to color2
let bkgView = MyBackgroundView()
// a dash-line to show the touch-point
let lineView = MyLineView()
// where we'll show the RGBA values
let outputLabel = UILabel()
// button to cycle through the 2nd colors
var btn: UIButton!
// references to the 4-variations of views (for convenience)
var views: [UIView] = []
// we'll "cache" the views, rendered to UIImages
var renderedViews: [UIImage] = []
let secondColors: [UIColor] = [
UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0),
UIColor(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0),
UIColor(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0),
UIColor(red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0),
]
let secondColorNames: [String] = [
"Red", "Green", "Blue", "Yellow",
]
var c2IDX: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
// references to the views
views = [gradientView1, gradientView2, layerView, bkgView]
let strs: [String] = [
"CAGradientLayer View1 (red -> color2)",
"CAGradientLayer View2 (color2 -> color2)",
"CALayer View (left red, right color2)",
"Background Color View (color2)"
]
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 4
for (str, v) in zip(strs, views) {
let label = UILabel()
label.text = str
v.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
stackView.addArrangedSubview(label)
stackView.addArrangedSubview(v)
stackView.setCustomSpacing(20.0, after: v)
}
[stackView, lineView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
lineView.topAnchor.constraint(equalTo: gradientView1.topAnchor, constant: -8.0),
lineView.leadingAnchor.constraint(equalTo: stackView.leadingAnchor, constant: 0.0),
lineView.trailingAnchor.constraint(equalTo: stackView.trailingAnchor, constant: 0.0),
lineView.bottomAnchor.constraint(equalTo: bkgView.bottomAnchor, constant: 12.0),
])
var config = UIButton.Configuration.filled()
config.buttonSize = .medium
config.cornerStyle = .medium
config.title = "Change 2nd Color to"
btn = UIButton(configuration: config)
btn.addAction (
UIAction { _ in
self.nextColor()
}, for: .touchUpInside
)
outputLabel.numberOfLines = 0
outputLabel.font = .systemFont(ofSize: 13, weight: .regular)
outputLabel.text = "RGBA at X:"
[btn, outputLabel].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
NSLayoutConstraint.activate([
btn.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 40.0),
btn.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
btn.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
outputLabel.topAnchor.constraint(equalTo: btn.bottomAnchor, constant: 20.0),
outputLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
outputLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
c2IDX = -1
nextColor()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
lineView.x = gradientView1.bounds.midX
gotTouch(lineView.x)
}
func genImages() {
// render the views to images each time we change the colors
// so we don't re-render them every time we want to get a color at a point
renderedViews = []
views.forEach { v in
renderedViews.append(v.renderView())
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let t = touches.first else { return }
let x = t.location(in: gradientView1).x
guard x >= 0.0, x <= gradientView1.bounds.maxX else { return }
gotTouch(x)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let t = touches.first else { return }
let x = t.location(in: gradientView1).x
guard x >= 0.0, x <= gradientView1.bounds.maxX else { return }
gotTouch(x)
}
func gotTouch(_ x: CGFloat) {
var outputStr: String = "RGBA at X: "
if UIScreen.main.scale == 3 {
// if the screen scale is @3x - such as an iPhone 14 Pro - we get 1/3 points
// so, display as .000 or .333 or .667 instead of .666666666667
outputStr += "\(String(format: "%0.3f", x))\n"
} else {
// @2x scale, so display as .0 or .5
outputStr += "\(String(format: "%0.1f", x))\n"
}
let strs: [String] = ["G1", "G2", "L", "B"]
for (str, img) in zip(strs, renderedViews) {
let pt: CGPoint = .init(x: x, y: img.size.height * 0.5)
if let c = img.getPixelColor(point: pt) {
// change "UIExtendedSRGBColorSpace 1 0 0 1" to "RGBA 1 0 0 1"
// just so we can focus on the color values
let s = "\(c)".replacingOccurrences(of: "UIExtendedSRGBColorSpace", with: "RGBA")
.replacingOccurrences(of: " ", with: " ")
outputStr += "\(str):\t\(s)\n"
}
}
lineView.x = x
outputLabel.text = outputStr
}
func nextColor() {
// cycle to the next "second color"
self.c2IDX += 1
let c = self.secondColors[self.c2IDX % self.secondColors.count]
self.views.forEach { v in
if let v = v as? MyBaseView {
v.c2 = c
}
}
// gradientView2 uses color2 -> color2 to appear "solid"
self.gradientView2.c1 = c
// let the views' layers update before we render new images from the views
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
// re-render the views
self.genImages()
// simiulate touch at last touch-point
self.gotTouch(self.lineView.x)
// update the button label
let cName = self.secondColorNames[(self.c2IDX + 1) % self.secondColorNames.count]
self.btn.configuration?.title = "Change 2nd Color to \(cName)"
})
}
}
**UIView subclasses**
class MyBaseView: UIView {
var c1: UIColor = .red { didSet { colorChanged() } }
var c2: UIColor = .red { didSet { colorChanged() } }
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
}
func colorChanged() {
}
}
class MyGradientView: MyBaseView {
let gradLayer = CAGradientLayer()
override func commonInit() {
super.commonInit()
gradLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradLayer.endPoint = CGPoint(x: 1, y: 0)
gradLayer.colors = [c1.cgColor, c2.cgColor]
layer.addSublayer(gradLayer)
}
override func layoutSubviews() {
super.layoutSubviews()
gradLayer.frame = bounds
}
override func colorChanged() {
super.colorChanged()
CATransaction.begin()
CATransaction.setDisableActions(true)
gradLayer.colors = [c1.cgColor, c2.cgColor]
CATransaction.commit()
}
}
class MyLayerView: MyBaseView {
let myLayer1 = CALayer()
let myLayer2 = CALayer()
override func commonInit() {
super.commonInit()
myLayer1.backgroundColor = c1.cgColor
myLayer2.backgroundColor = c2.cgColor
layer.addSublayer(myLayer1)
layer.addSublayer(myLayer2)
}
override func layoutSubviews() {
super.layoutSubviews()
var r = bounds
r.size.width *= 0.5
myLayer1.frame = r
r.origin.x = r.size.width
myLayer2.frame = r
}
override func colorChanged() {
super.colorChanged()
CATransaction.begin()
CATransaction.setDisableActions(true)
myLayer1.backgroundColor = c1.cgColor
myLayer2.backgroundColor = c2.cgColor
CATransaction.commit()
}
}
class MyBackgroundView: MyBaseView {
override func commonInit() {
super.commonInit()
backgroundColor = c2
}
override func colorChanged() {
super.colorChanged()
backgroundColor = c2
}
}
class MyLineView: UIView {
var x: CGFloat = 0 { didSet { setNeedsLayout() } }
// this allows us to use the "base" layer as a shape layer
// instead of adding a sublayer
lazy var shapeLayer: CAShapeLayer = self.layer as! CAShapeLayer
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
layer.masksToBounds = true
shapeLayer.strokeColor = UIColor.gray.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 1
shapeLayer.lineDashPattern = [8, 8]
}
override func layoutSubviews() {
super.layoutSubviews()
let bez = UIBezierPath()
bez.move(to: .init(x: x, y: bounds.minY))
bez.addLine(to: .init(x: x, y: bounds.maxY))
CATransaction.begin()
CATransaction.setDisableActions(true)
shapeLayer.path = bez.cgPath
CATransaction.commit()
}
}
[1]: https://i.stack.imgur.com/VTEYp.png
[2]: https://i.stack.imgur.com/y2tzN.png
[3]: https://i.stack.imgur.com/Qvac2.png
[4]: https://i.stack.imgur.com/qrq05.png
</details>
# 答案2
**得分**: 0
以下是翻译好的内容:
"that's odd! Is this the only code that involves with this part of code? I just tested and got true result :
这很奇怪!这是唯一涉及到这部分代码的吗?我刚刚测试并获得了正确的结果:
Copy and paste this code in a new Xcode project and check if you still get the wrong result.
复制并粘贴这段代码到一个新的Xcode项目中,然后检查是否仍然得到错误的结果。
import UIKit
class ViewController: UIViewController {
let gradientLayer2 = CAGradientLayer()
let slider = UISlider(frame: CGRect(x: 10, y: 400, width: 100, height: 50))
override func viewDidLoad() {
super.viewDidLoad()
slider.maximumValue = 1
slider.minimumValue = 0
slider.addTarget(self, action: #selector(sliderChanged), for: .valueChanged)
slider.backgroundColor = .red
gradientLayer2.frame.size = CGSize(width: 200, height: 200)
gradientLayer2.colors = [
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor,
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor
]
gradientLayer2.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer2.endPoint = CGPoint(x: 1, y: 0)
gradientLayer2.cornerRadius = 20
view.layer.insertSublayer(gradientLayer2, at: 0)
view.addSubview(slider)
}
@objc func sliderChanged()
{
gradientLayer2.colors = [
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor,
UIColor(red: CGFloat(slider.value), green: 0.00, blue: 0.00, alpha: 1.00).cgColor
]
print(gradientLayer2.colors)
}"
希望对你有所帮助。
<details>
<summary>英文:</summary>
that's odd! Is this the only code that involves with this part of code? I just tested and got true result :
Optional([<CGColor 0x6000002bd6e0> [<CGColorSpace 0x6000002b9980> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)] ( 1 0 0 1 ), <CGColor 0x6000002bd2c0> [<CGColorSpace 0x6000002b9980> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)] ( 1 0 0 1 )])
Copy and paste this code in a new Xcode project and check if you still get the wrong result.
import UIKit
class ViewController: UIViewController {
let gradientLayer2 = CAGradientLayer()
let slider = UISlider(frame: CGRect(x: 10, y: 400, width: 100, height: 50))
override func viewDidLoad() {
super.viewDidLoad()
slider.maximumValue = 1
slider.minimumValue = 0
slider.addTarget(self, action: #selector(sliderChanged), for: .valueChanged)
slider.backgroundColor = .red
gradientLayer2.frame.size = CGSize(width: 200, height: 200)
gradientLayer2.colors = [
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor,
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor
]
gradientLayer2.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer2.endPoint = CGPoint(x: 1, y: 0)
gradientLayer2.cornerRadius = 20
view.layer.insertSublayer(gradientLayer2, at: 0)
view.addSubview(slider)
}
@objc func sliderChanged()
{
gradientLayer2.colors = [
UIColor(red: 1.00, green: 0.00, blue: 0.00, alpha: 1.00).cgColor,
UIColor(red: CGFloat(slider.value), green: 0.00, blue: 0.00, alpha: 1.00).cgColor
]
print(gradientLayer2.colors)
}
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论