Вы должны обновить маску в переопределении layoutSubviews
. Когда ограничения обновляют frame
представления, вызывается layoutSubviews
, так что это правильное место для обновления маски.
В качестве отступления, я бы не рекомендовал использовать awakeFromNib
для настройки представления. Он прекрасно работает, если вы используете раскадровку, но программно созданные представления не будут вызывать это. Если вы хотите настроить представление при его создании, лучше поместить код в какой-то частный метод настройки, который вызывается init(frame:)
и init(coder:)
. Таким образом, он работает как для раскадровок, так и для программно созданных представлений.
Я мог бы также предложить наблюдателям по проверяемым свойствам вызвать обновление округления угла. Вы хотите, чтобы закругление углов обновлялось автоматически при изменении этих свойств.
Таким образом:
@IBDesignable
public class RoundedView: UIView {
@IBInspectable public var topLeft: Bool = false { didSet { setNeedsLayout() } }
@IBInspectable public var topRight: Bool = false { didSet { setNeedsLayout() } }
@IBInspectable public var bottomLeft: Bool = false { didSet { setNeedsLayout() } }
@IBInspectable public var bottomRight: Bool = false { didSet { setNeedsLayout() } }
@IBInspectable public var cornerRadius: CGFloat = 0 { didSet { setNeedsLayout() } }
public override func layoutSubviews() {
super.layoutSubviews()
var options = UIRectCorner()
if topLeft { options.formUnion(.topLeft) }
if topRight { options.formUnion(.topRight) }
if bottomLeft { options.formUnion(.bottomLeft) }
if bottomRight { options.formUnion(.bottomRight) }
let path = UIBezierPath(roundedRect: bounds,
byRoundingCorners: options,
cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
layer.mask = maskLayer
}
}
Или, в качестве альтернативы, если нацелена на iOS 11 и более поздние версии, мы можем позволить CoreAnimation выполнить округление:
@IBDesignable
public class RoundedView: UIView {
@IBInspectable public var topLeft: Bool = false { didSet { updateCorners() } }
@IBInspectable public var topRight: Bool = false { didSet { updateCorners() } }
@IBInspectable public var bottomLeft: Bool = false { didSet { updateCorners() } }
@IBInspectable public var bottomRight: Bool = false { didSet { updateCorners() } }
@IBInspectable public var cornerRadius: CGFloat = 0 { didSet { updateCorners() } }
public override init(frame: CGRect = .zero) {
super.init(frame: frame)
updateCorners()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
updateCorners()
}
}
private extension RoundedView {
func updateCorners() {
var corners = CACornerMask()
if topLeft { corners.formUnion(.layerMinXMinYCorner) }
if topRight { corners.formUnion(.layerMaxXMinYCorner) }
if bottomLeft { corners.formUnion(.layerMinXMaxYCorner) }
if bottomRight { corners.formUnion(.layerMaxXMaxYCorner) }
layer.maskedCorners = corners
layer.cornerRadius = cornerRadius
}
}
Хорошая вещь в этом последнем подходе заключается в том, что CoreAnimation будет соблюдать округление нашего угла, если мы получим анимацию frame
представления:
Если вы используете вышеупомянутый подход layoutSubviews
, вам придется управлять анимацией вручную (например, с помощью CADisplayLink
).