Skip to main content

Layer corners

Чтобы задать какой либо вью скругленные края, нужно у его layer'а, поменять значение поля cornerRadius на радиус скругления. Пример:

submitButton.layer.cornerRadius = 16

В итоге получаем следующую картину: fullRound

Но что делать, если необходимо, чтобы скругления были только снизу или сверху. Начиная с iOS 11.0 у CALayer появилось свойство maskedCorners, оно позволяет выбрать список углов, которые надо скруглить.

maskedCorners имеет тип CACornerMask и может принимать значения:

  • layerMaxXMaxYCorner -> Правый нижний угол
  • layerMaxXMinYCorner -> Правый верхний угол
  • layerMinXMaxYCorner -> Левый нижний угол
  • layerMinXMinYCorner -> Левый верхний угол

При этом можно выбрать любое количество углов. Примеры:

Так можно задать скругления только снизу:

submitButton.layer.cornerRadius = 16
submitButton.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]

bottomRound

А так можно задать скругление только левого верхнего угла:

submitButton.layer.cornerRadius = 16
submitButton.layer.maskedCorners = .layerMinXMinYCorner

topLeftRound

Однако есть случаи, когда этого недостаточно. Например, если добавить кнопке backgroundImage, то скругления пропадут.

submitButton.setBackgroundImage(UIImage(named: "balearic-islands-31_1280")!, for: .normal)
submitButton.layer.cornerRadius = 16
submitButton.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]

backImageNotRound

Это происходит по причине того, что по дефолту скругления не применяются к картинкам внутри леера (о чем написано в документации). Для того чтобы скругления применялись к картинкам, необходимо присвоить свойству masksToBounds значение true.

submitButton.setBackgroundImage(UIImage(named: "balearic-islands-31_1280")!, for: .normal)
submitButton.layer.cornerRadius = 16
submitButton.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
submitButton.layer.masksToBounds = true

После добавления maskToBounds, скругленные края появляются вновь: backImageRound

Рассмотрим еще один случай. К той же самой кнопке, помимо всего прочего, добавим еще и тень вокруг кнопки:

submitButton.setBackgroundImage(UIImage(named: "balearic-islands-31_1280")!, for: .normal)
submitButton.layer.cornerRadius = 16
submitButton.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
submitButton.layer.masksToBounds = true

submitButton.layer.shadowColor = UIColor.black.cgColor
submitButton.layer.shadowOffset = CGSize(width: 0, height: 2)
submitButton.layer.shadowRadius = 10
submitButton.layer.shadowOpacity = 0.5

Тень вокруг кнопки не появилась потому, что она обрезается свойством masksToBounds. Можно выключить маску и тогда тень появится, но перестанет обрезаться картинка на фоне. Итак, как же выйти из сложившейся ситуации, в интернете есть множество разных вариантов решения данной проблемы, я же приведу только один, который мне больше нравится. Убираем добавление backgroundImage и masksToBounds для кнопки. Вместо этого создаем свой собственный CALayer, задаем ему размер как у кнопки, а контент делаем равным нашему изображению. И уже этому слою выставляем masksToBounds = true.

        submitButton.layer.cornerRadius = 16
submitButton.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
submitButton.layer.shadowColor = UIColor.black.cgColor
submitButton.layer.shadowOffset = CGSize(width: 0, height: 2)
submitButton.layer.shadowRadius = 10
submitButton.layer.shadowOpacity = 0.5

let backgroundLayer = CALayer()
backgroundLayer.frame = submitButton.bounds
backgroundLayer.contents = UIImage(named: "balearic-islands-31_1280")!.cgImage
backgroundLayer.cornerRadius = 16
backgroundLayer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
backgroundLayer.masksToBounds = true
submitButton.layer.insertSublayer(backgroundLayer, at: 0)

В результате получаем кнопку с тенью, фоновым изображением и закругленными краями. finaleState

На этом у меня все, более подробно про работу с Layer'ами можно прочитать в статье UIKit ты вообще про UI?.

Автор: @Dorofeev