Пара наблюдений:
Вы звоните setFill
, а затем fill
, но вы делаете это только при рисовании в графическом контексте (например, в draw(_:)
).При использовании CAShapeLayer
вместо этого следует установить fillColor
из CAShapeLayer
.
Вы используете CAShapeLayer
для установки маскиваш взгляд.Если у вашего UIView
нет различимого backgroundColor
, вы ничего не увидите.
Если вы установите цвет фона вида, скажем, синий, как показано ниже, ваша маска будетпокажите этот синий фон везде, где маска позволяет (в овале вашего пути).
Вы реализовали layoutSubviews
.Обычно вы делаете это только в том случае, если вы делаете здесь что-то, что зависит от bounds
представления.Например, вот представление, в котором овальный путь основан на bounds
представления:
@IBDesignable
class CircleView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
setupMask()
}
private func setupMask() {
let mask = CAShapeLayer()
mask.path = path.cgPath
mask.fillColor = UIColor.gray.cgColor
layer.mask = mask
}
private var path: UIBezierPath {
return UIBezierPath(ovalIn: bounds)
}
}
Как сказал E. Coms, если вы переопределите layoutSubviews
, выдействительно следует вызвать реализацию super
.Это не критично, так как реализация по умолчанию ничего не делает, но это лучшая практика.Например, если вы позже изменили этот класс на подкласс какого-то другого подкласса UIView
, вам не нужно будет пересматривать все эти переопределения.
Если у вас есть проектируемое представление,желательно поместить это в отдельную цель.Таким образом, отображение представления в раскадровке не зависит от какой-либо работы, которая может выполняться в основном проекте.До тех пор, пока цель designables (часто имя вашей главной цели с суффиксом Kit
) может создаваться, designable view может быть визуализирован.
Например, здесь приведено отображениеваш проектируемый вид, в отдельной целевой структуре и используемый в раскадровке, где рассматриваемый вид имеет синий цвет backgroundColor
:
Для чего это стоит, я думаю, что это очень сбивает с толку необходимость маскировать, чтобы показать цвет фона внутри овала.Разработчик приложения должен установить «фоновый» цвет, чтобы установить то, что находится внутри овала, но не фон.
Я мог бы вместо этого удалить логику «маски» и вместо этого дать проектируемому представлению проверяемое свойство, fillColor
, и просто добавьте CAShapeLayer
в качестве подслоя, используя этот fillColor
:
@IBDesignable
class CircleView: UIView {
private var shapeLayer = CAShapeLayer()
@IBInspectable var fillColor: UIColor = .blue {
didSet {
shapeLayer.fillColor = fillColor.cgColor
}
}
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
private func configure() {
shapeLayer.fillColor = fillColor.cgColor
layer.addSublayer(shapeLayer)
}
override func layoutSubviews() {
super.layoutSubviews()
shapeLayer.path = UIBezierPath(ovalIn: bounds).cgPath
}
}
Это делает то же самое, но я думаю, что различие между цветами заливки и цветами фона более интуитивно понятно.Но у вас могут быть другие причины для использования маскирующего подхода, но просто убедитесь, что если вы это сделаете, вам есть что показать после маскировки (например, цвет фона или что-то еще, что вы визуализируете).