Constraints обрезают наложенный Sublayer на UIButton
Сделал кнопку с закругленными краями, наложил сверху слой рамки с градиентом. Отдельно она рисуется как нужно, но после интеграции на основной экран и записи Constraints её верхний слой начинает обрезаться. (На скрине это видно справа и снизу кнопки)

Кнопка: mainSearchButtonView
Constraints задаются в initialize()
Sublayer накладывается при помощи расширения UIView.addGradientCornerBorders(...)
import UIKit
class ViewController: UIViewController {
private let screenSize: CGRect = UIScreen.main.bounds
private lazy var titleTopOffset: CGFloat = screenSize.height * 0.045
private let cardWidthCoeff: Double = 0.9
private let cardHeightCoeff: Double = 0.25
private lazy var cardButtonWidthCoeff: Double = cardWidthCoeff * 0.3
private lazy var cardButtonHeightCoeff: Double = cardHeightCoeff * 1.05
private lazy var scrollView: UIScrollView = {
let view = UIScrollView()
view.translatesAutoresizingMaskIntoConstraints = false
view.showsVerticalScrollIndicator = false
view.contentInsetAdjustmentBehavior = .never
return view
}()
private lazy var titleStackView: UIStackView = {
let view = UIStackView()
view.translatesAutoresizingMaskIntoConstraints = false
view.axis = .horizontal
view.spacing = 5
return view
}()
private lazy var mainIconView: UIImageView = {
let view = UIImageView()
let image = UIImage(systemName: "location.viewfinder")?.resized(to: CGSize(width: screenSize.width * 0.11, height: screenSize.width * 0.11 * 7 / 8)) ?? UIImage()
view.image = image
view.tintColor = .black
view.contentMode = .scaleAspectFit
return view
}()
private lazy var mainLabelView: UILabel = {
let view = UILabel()
view.adjustsFontSizeToFitWidth = true
view.minimumScaleFactor = 0.2
view.numberOfLines = 1
view.text = "label1"
view.textAlignment = .center
view.font = UIFont.systemFont(ofSize: screenSize.width * 0.095, weight: .bold)
view.textColor = .black
return view
}()
private let mainCardView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor(red: 241/255, green: 238/255, blue: 228/255, alpha: 1)
view.layer.cornerRadius = 25
view.layer.shadowColor = UIColor.gray.cgColor
view.layer.shadowOpacity = 1
view.layer.shadowOffset = .zero
view.layer.shadowRadius = 5
return view
}()
private lazy var mainSearchButtonView: UIButton = {
let image = UIImage(systemName: "magnifyingglass")?.resized(to: CGSize(width: screenSize.width * 0.11, height: screenSize.width * 0.11 * 7 / 8))
let cornerRadius: Double = 25.0
let view = UIButton(type: .system)
view.translatesAutoresizingMaskIntoConstraints = false
view.setTitle("", for: .normal)
view.setImage(image, for: .normal)
view.tintColor = .black
view.frame.size = CGSize(width: screenSize.width * cardButtonWidthCoeff, height: screenSize.height * cardButtonHeightCoeff)
view.backgroundColor = UIColor(red: 241/255, green: 238/255, blue: 228/255, alpha: 1)
view.layer.cornerRadius = cornerRadius
view.addGradientCornerBorders(lineWidth: 10, cornerRadius: cornerRadius, colors: [UIColor.blue.cgColor, UIColor.green.cgColor], startPoint: CGPoint.topRight, endPoint: CGPoint.bottomLeft)
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
initialize()
}
private func initialize() {
overrideUserInterfaceStyle = .light
view.backgroundColor = UIColor(red: 241/255, green: 238/255, blue: 228/255, alpha: 1)
view.addSubview(scrollView)
scrollView.addSubview(titleStackView)
scrollView.addSubview(mainCardView)
titleStackView.addArrangedSubview(mainIconView)
titleStackView.addArrangedSubview(mainLabelView)
mainCardView.addSubview(mainSearchButtonView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
titleStackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: titleTopOffset),
titleStackView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
mainCardView.topAnchor.constraint(greaterThanOrEqualTo: titleStackView.bottomAnchor, constant: screenSize.height * 0.05),
mainCardView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
mainCardView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: cardWidthCoeff),
mainCardView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: cardHeightCoeff),
mainSearchButtonView.centerYAnchor.constraint(equalTo: mainCardView.centerYAnchor),
mainSearchButtonView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: cardButtonWidthCoeff),
mainSearchButtonView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: cardButtonHeightCoeff),
mainSearchButtonView.rightAnchor.constraint(equalTo: mainCardView.rightAnchor, constant: 10)
])
}
extension CGPoint {
static let topLeft = CGPoint(x: 0, y: 0)
static let topCenter = CGPoint(x: 0.5, y: 0)
static let topRight = CGPoint(x: 1, y: 0)
static let centerLeft = CGPoint(x: 0, y: 0.5)
static let center = CGPoint(x: 0.5, y: 0.5)
static let centerRight = CGPoint(x: 1, y: 0.5)
static let bottomLeft = CGPoint(x: 0, y: 1.0)
static let bottomCenter = CGPoint(x: 0.5, y: 1.0)
static let bottomRight = CGPoint(x: 1, y: 1)
}
extension UIImage {
func resized(to size: CGSize) -> UIImage {
return UIGraphicsImageRenderer(size: size).image { _ in
draw(in: CGRect(origin: .zero, size: size))
}
}
}
extension UIView {
func addGradientCornerBorders(lineWidth: CGFloat, cornerRadius: Double, colors: [CGColor], startPoint: CGPoint = CGPoint.topCenter, endPoint: CGPoint = CGPoint.bottomCenter) {
let gradient = CAGradientLayer()
gradient.frame.size = self.frame.size
gradient.colors = colors
gradient.startPoint = startPoint
gradient.endPoint = endPoint
let shape = CAShapeLayer()
shape.lineWidth = lineWidth
shape.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: cornerRadius).cgPath
shape.strokeColor = UIColor.black.cgColor
shape.fillColor = UIColor.clear.cgColor
gradient.mask = shape
self.clipsToBounds = true
self.layer.addSublayer(gradient)
}
}
Ответы (1 шт):
Автор решения: Oleg Soloviev
→ Ссылка
Посмотрел на SE. Тут, возможно, артефакты из-за не круглых значений, которые используются для расчета углов. Попробуйте поэкспериментировать с коэффициентами, например так:
private lazy var cardButtonWidthCoeff: Double = cardWidthCoeff * 0.32
private lazy var cardButtonHeightCoeff: Double = cardHeightCoeff * 1.06
