I have a non-transparent UIView with UILabel of white non-transparent color. I display it as a subview in some view with border. And I can see that border in my UILabel's letters...
By the way, I've tried to overlap content in my superview and it's been rendered absolutely fine - so the issue is existing only with the border.
I assume there's something wrong on the render layer when it blends border of the superview and letters of the UILabel
Code for TagView and it's superview:
import UIKit
import PlaygroundSupport
enum TagType {
case minimal
case rounded
case circle
}
class TagView: UIView {
var tagType: TagType = .rounded { didSet { updateUI() }}
var isSelected = false { didSet { updateUI() }}
private(set) lazy var label: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
label.clipsToBounds = true
label.font = .systemFont(ofSize: 15, weight: .semibold)
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
private var leadingLabelAnchor: NSLayoutConstraint?
private var trailingLabelAnchor: NSLayoutConstraint?
private var topLabelAnchor: NSLayoutConstraint?
private var bottomLabelAnchor: NSLayoutConstraint?
var constantValue: CGFloat {
tagType == .circle ? 12 : 8
}
var verticalInsetTop: CGFloat {
tagType == .minimal ? 3 : 5
}
var verticalInsetBottom: CGFloat {
tagType == .minimal ? 3 : 7
}
private func setup() {
clipsToBounds = true
addSubview(label)
leadingLabelAnchor = label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: constantValue)
trailingLabelAnchor = label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -constantValue)
leadingLabelAnchor?.priority = .defaultHigh
leadingLabelAnchor?.isActive = true
trailingLabelAnchor?.priority = .defaultHigh
trailingLabelAnchor?.isActive = true
topLabelAnchor = label.topAnchor.constraint(equalTo: topAnchor, constant: verticalInsetTop)
topLabelAnchor?.isActive = true
bottomLabelAnchor = label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -verticalInsetBottom)
bottomLabelAnchor?.isActive = true
layer.borderColor = UIColor.blue.cgColor
layer.borderWidth = 1
updateUI()
}
override func layoutSubviews() {
super.layoutSubviews()
updateUI()
}
private func updateUI() {
leadingLabelAnchor?.constant = constantValue
trailingLabelAnchor?.constant = -constantValue
topLabelAnchor?.constant = verticalInsetTop
bottomLabelAnchor?.constant = -verticalInsetBottom
backgroundColor = isSelected ? .blue : .clear
label.backgroundColor = backgroundColor
label.textColor = isSelected ? .white : .blue
switch tagType {
case .minimal:
layer.cornerRadius = 10
case .rounded:
layer.cornerRadius = 12
case .circle:
layer.cornerRadius = bounds.height / 2
}
}
func configure(with text: String) {
label.text = text
}
}
final class MyControl: UIControl {
private lazy var tagView: TagView = {
let view = TagView()
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
tagView.translatesAutoresizingMaskIntoConstraints = false
tagView.isSelected = true
backgroundColor = .clear
layer.cornerRadius = 10
layer.borderWidth = 2
layer.borderColor = UIColor.blue.cgColor
addSubview(tagView)
NSLayoutConstraint.activate(
[
tagView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8),
tagView.topAnchor.constraint(equalTo: topAnchor, constant: -16)
]
)
tagView.configure(with: "7 dayyyyy")
}
}
class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let label = UILabel()
label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
label.text = "Hello World!"
label.textColor = .black
let myControl = MyControl()
myControl.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myControl)
NSLayoutConstraint.activate([
myControl.centerXAnchor.constraint(equalTo: view.centerXAnchor),
myControl.centerYAnchor.constraint(equalTo: view.centerYAnchor),
myControl.widthAnchor.constraint(equalToConstant: 300),
myControl.heightAnchor.constraint(equalToConstant: 50),
])
view.addSubview(label)
self.view = view
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

Only workaround I found for now, not to apply to parent view's layer border width and color, but to add additional subview with border to this parent views so the tag view is not a subview of a new background bordered view: