带有背景颜色的 UIView 看起来不同于带有背景颜色的 CALayer。为什么,以及如何使它们匹配?

UIView with background color looks different than CALayer with background color. Why, and how to make them match?

我创建了一个小项目 (Github link) demonstrating how to add a line under a UITextField to answer .

OP 试图使用 CALayer 添加下划线,所以这就是我最初实现解决方案的方式。对于那个版本,我创建了一个名为“UnderlinedTextField”的 UITextField 的自定义子 class。该自定义 subclass 创建并维护具有背景颜色的 CALayer。

然后我注意到在文本字段的底部简单地添加一个 1 点 UIView 会更容易。我也更新了我的演示项目来说明该方法。

两种方法都在 UITextField 下方添加了一条 1 点蓝线。基于视图的方法在 Storyboard 中完成所有操作,并且不需要代码。由于它使用 AutoLayout 约束将下划线视图固定到文本字段的底部,因此即使文本字段移动,约束也会将视图保持在正确的位置。

但是,我注意到基于图层的下划线和基于视图的下划线看起来不同这里是截图:

基于图层的下划线看起来更重了。在看它时,用于基于图层的下划线抗锯齿的颜色比用于基于视图的下划线用于抗锯齿下划线的颜色深。

为什么会这样,我要改变什么才能让它们看起来一样?

(以下是 UnderlinedTextField class 的代码,以防你不想去查看 Github 存储库)

/// This is a custom subclass of UITextField that adds a 1-point colored underline under the text field using a CALayer.
/// It implments the `layoutSubviews()` method to reposition the underline layer if the text field is moved or resized.
class UnderlinedTextField: UITextField {

    /// Change this color to change the color used for the underline
    public var underlineColor = UIColor.blue {
        didSet {
            underlineLayer.backgroundColor = underlineColor.cgColor
        }
    }

    private let underlineLayer = CALayer()

    /// Size the underline layer and position it as a one point line under the text field.
    func setupUnderlineLayer() {
        var frame = self.bounds
        frame.origin.y = frame.size.height - 1
        frame.size.height = 1

        underlineLayer.frame = frame
        underlineLayer.backgroundColor = underlineColor.cgColor
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        // In `init?(coder:)` Add our underlineLayer as a sublayer of the view's main layer
        self.layer.addSublayer(underlineLayer)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        // in `init(frame:)` Add our underlineLayer as a sublayer of the view's main layer
        self.layer.addSublayer(underlineLayer)
    }

    // Any time we are asked to update our subviews,
    // adjust the size and placement of the underline layer too
    override func layoutSubviews() {
        super.layoutSubviews()
        setupUnderlineLayer()
    }
}

编辑:

我根据 Matt 的回答更改了我的项目(并推送了更改)以使 Storyboard 使用设备颜色配置文件。这使得下划线的颜色值 非常 接近,但仍然不完全相同。

如果我使用“数字色度计”应用程序检查模拟器中的线条,顶部和底部的线条会略有不同。但是,如果我使用控件 S 将屏幕保存到模拟器中的磁盘(以全尺寸保存)并在 PS 中打开生成的图像,这些线条显示为未混叠的纯 sRGB 蓝色。我猜想将模拟器屏幕映射到 Mac 屏幕有些奇怪,这会导致 2 行的别名略有不同。

(您必须在 PS 或其他可让您查看像素颜色的应用程序中打开图片以检测两条线的差异。将故事板的颜色配置文件更改为设备 RGB (sRGB) 后我再也看不出区别了。)

你实际上给了它们不同的颜色。

  • 层的颜色在代码中设置为UIColor.blue.cgColor

  • 视图的颜色是在情节提要中创建的

      R:0.02 G:0.2 B:1 A:1
    

    正如在视图调试器中检查它所显示的那样。

为什么?因为你没有考虑故事板颜色的颜色space。它是通用 RGB,而您在代码中创建的颜色是设备 RGB,即 sRGB.

查看此内容的另一种方法是进行一些日志记录。在 运行 应用程序中,两种颜色是

<CGColor 0x60000296aa60> 
[<CGColorSpace 0x60000296ab20> 
    (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)] 
( 0 0 1 1 )>

<CGColor 0x600002976940> 
[<CGColorSpace 0x60000296ab20> 
    (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)] 
( 0.01675 0.198341 1 1 )>

如您所见,第二种颜色已转换为 sRGB 颜色 space,这与您开始时使用的 Generic RGB 不同,因此我们在之后得到了不同的颜色转换。

and what would I change to make them look the same

如果您将情节提要颜色的颜色space设置为Device RGB,然后将滑块设置为简单的蓝色,您最终会在运行中得到相同的颜色应用