CAGradientLayer 位置不正确

Posted

技术标签:

【中文标题】CAGradientLayer 位置不正确【英文标题】:CAGradientLayer locations not coming correct 【发布时间】:2018-07-05 10:58:08 【问题描述】:

我关注this 设置渐变位置的帖子。

我的代码:

let color1 = UIColor(red: 0.0/255.0, green: 231.0/255.0, blue: 198.0/255.0, alpha: 0.9).cgColor as CGColor
let color2 = UIColor(red: 0.0/255.0, green: 198.0/255.0, blue: 255.0/255.0, alpha: 0.9).cgColor as CGColor      
self.gradientLayer.colors = [color2, color1, color2]
self.gradientLayer.locations = [0.0, 0.10, 0.9]
self.gradientLayer.startPoint = CGPoint(x: 0, y: 0)
self.gradientLayer.endPoint = CGPoint(x: 1, y: 1)
viewMain.layer.insertSublayer(self.gradientLayer, at: 0)  

我的输出:

预期输出:

【问题讨论】:

gradientLayer.colors = [color2, color1, color1, color2]; gradientLayer.locations = [0.0, 0.2, 0.8, 1.0]?您需要了解这意味着颜色将位于您提供的位置。但在你的代码中是[0.0, 0.10, 0.9]。所以想象一下在 0 处写一条蓝线,在 0.1 处写一条绿线,在 0.9 处写一条蓝线。 (根据您的起点/终点以对角线方式)。现在在每条线之间应用颜色的渐变(“两条连续线的两个渐变在中途相遇”)。那么你得到之前的输出而不是预期的输出是正常的。 @Larme :抱歉,我很难理解这一点。 但是我给出的颜色/位置使它起作用了?我正在做一个视觉解释。可能会在几个小时后到(在家里做) @Larme:确实如此。确实如此。 cgColor as CGColor 从 CGColor 转换为 CGColor 是没有意义的 【参考方案1】:

为了说明,我更改了startPoint/endPoint。 此代码可在 XCode Playground 中使用。这不是最好的 Swifty 代码,而是专注于逻辑/解释而不是纯 Swift 代码

共享设置:

import Foundation
import UIKit

let viewsWidth: CGFloat = 300.0
let viewsHeight: CGFloat = 400.0

修复代码的方法是修改locations:

let viewMain: UIView = UIView(frame: CGRect(x: 0, y: 0, width: viewsWidth, height: viewsHeight))
let color1 = UIColor(red: 0.0/255.0, green: 231.0/255.0, blue: 198.0/255.0, alpha: 0.9).cgColor
let color2 = UIColor(red: 0.0/255.0, green: 198.0/255.0, blue: 255.0/255.0, alpha: 0.9).cgColor
var gradientLayer = CAGradientLayer.init()
gradientLayer.frame = viewMain.bounds
gradientLayer.colors = [color2, color1, color1, color2]
gradientLayer.locations = [0.0, 0.2, 0.8, 1.0]
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
viewMain.layer.insertSublayer(gradientLayer, at: 0)

viewMain //That's just for the Show Result action in Playground

ViewMain:

现在做一些解释。

让我们先在每个位置画一条线:

let otherView = UIView(frame: viewMain.bounds)
if let locations = gradientLayer.locations, let colors = gradientLayer.colors 
    for (index, aLocation) in locations.enumerated() 
        let aLine = UIView(frame: CGRect(x: viewsWidth*CGFloat(aLocation.floatValue)-2,
                                         y: 0,
                                         width: 4,
                                         height: viewsHeight))
        aLine.backgroundColor = UIColor(cgColor: colors[index] as! CGColor)
        otherView.addSubview(aLine)
    


otherView //That's just for the Show Result action in Playground

其他视图:

现在,让我们为每一行绘制一个渐变,但只有一个(其余颜色设置为白色以简化)。

if let locations = gradientLayer.locations, let colors = gradientLayer.colors 
    let offset = 5
    let bigView = UIView(frame: CGRect(x: 0,
                                       y: 0,
                                       width: viewsWidth * CGFloat(locations.count) + CGFloat(offset),
                                       height: viewsHeight))

    for (index, _) in locations.enumerated() 

        let aGradientView = UIView(frame: CGRect(x: 0 + (viewsWidth + CGFloat(offset))*CGFloat(index),
                                                 y: 0,
                                                 width: viewsWidth,
                                                 height: viewsHeight))
        let aGradientLayer = CAGradientLayer()
        aGradientLayer.frame = aGradientView.bounds

        var aGradientColors = [CGColor](repeating: UIColor.white.cgColor, count: colors.count)
        aGradientColors[index] = colors[index] as! CGColor
        aGradientLayer.colors = aGradientColors
        aGradientLayer.locations = gradientLayer.locations
        aGradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
        aGradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        aGradientView.layer.insertSublayer(aGradientLayer, at: 0)

        aGradientView.layer.borderColor = UIColor.black.cgColor
        aGradientView.layer.borderWidth = 2.0
        aGradientView.clipsToBounds = false
        bigView.addSubview(aGradientView)
    

    bigView //That's just for the Show Result action in Playground

大视图:

图示说明了一切。

在每一“行”(图表 2),当您想要应用渐变(图表 3)时,颜色会从该行一直到下一行。这就是为什么您的第一个位置没有给出预期的结果。您需要放置中间步骤。

【讨论】:

非常感谢您的意见@Larne。虽然您的评论昨天帮助解决了这个问题,但这足以说明问题。

以上是关于CAGradientLayer 位置不正确的主要内容,如果未能解决你的问题,请参考以下文章

CAGradientLayer 没有正确绘制渐变

CAGradientLayer 获取像素颜色

Swift 中的 CAGradientLayer 位置

渐变层不在正确的位置

CAGradientLayer 自转

使用 CABasicAnimation 后防止 CAGradientLayer 位置返回原始值