Маскированный CALayer в iOS
Я пытаюсь создать ярлык (или любой другой вид в этом отношении) с одним закругленным углом и штрихом/границей. Я могу достичь первого, используя следующий код:
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.label.bounds
byRoundingCorners:UIRectCornerBottomRight
cornerRadii:CGSizeMake(16.0f, 16.0f)];
CAShapeLayer *shape = [CAShapeLayer layer];
shape.frame = self.label.bounds;
shape.path = maskPath.CGPath;
self.label.layer.mask = shape;
Что отлично подходит для закругленного угла, но использование следующего кода не влияет на ход так, как я хочу. Вместо того, чтобы создать черный (или что-то из backgroundColor
of self.label
установлено) квадратная.
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.label.bounds
byRoundingCorners:UIRectCornerBottomRight
cornerRadii:CGSizeMake(16.0f, 16.0f)];
CAShapeLayer *shape = [CAShapeLayer layer];
shape.frame = self.label.bounds;
shape.path = maskPath.CGPath;
// Add stroke
shape.borderWidth = 1.0f;
shape.borderColor = [UIColor whiteColor].CGColor;
self.label.backgroundColor = [UIColor blackColor];
self.label.layer.mask = shape;
Любые предложения о том, как я могу применить произвольный цветной штрих, следующий за маскированным путем?
Ответы
Ответ 1
Вы на правильном пути с слоем формы. Но у вас должно быть два разных слоя. Сначала слой маски, как в первом примере, который маскирует ваше представление (отсекает области, которые вы не хотите видеть)
Затем вы добавляете слой формы, но не как слой маски. Кроме того, убедитесь, что не используйте borderWidth и borderColor, но выполните штрих.
//
// Create your mask first
//
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.label.bounds
byRoundingCorners:UIRectCornerBottomRight
cornerRadii:CGSizeMake(16.0f, 16.0f)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = self.label.bounds;
maskLayer.path = maskPath.CGPath;
self.label.layer.mask = maskLayer;
//
// And then create the outline layer
//
CAShapeLayer *shape = [CAShapeLayer layer];
shape.frame = self.label.bounds;
shape.path = maskPath.CGPath;
shape.lineWidth = 3.0f;
shape.strokeColor = [UIColor whiteColor].CGColor;
shape.fillColor = [UIColor clearColor].CGColor;
[self.label.layer addSublayer:shape];
Имейте в виду, что ваш путь слоя инсульта должен быть внутри (меньше) пути к маске. В противном случае поглаженный путь будет замаскирован слоем маски. Я установил lineWith в 3, что делает его таким, чтобы вы могли видеть половину ширины (1,5 px), а другая половина будет вне маски.
Ответ 2
Если вы подклассом CALayer
, вы можете создать его с помощью маски, которую хотите, а также переопределить layoutSubLayers
, чтобы включить рамку, которую вы хотите в этой маске.
Мог бы сделать это несколько способов. Ниже я делаю это, используя path
данной маски и присваивая это свойству классу, которое будет использоваться для построения новой границы в layoutSubLayers
. Существует потенциал, что этот метод можно было бы назвать несколько раз, поэтому я также задал логическое значение для отслеживания этого. (Также можно назначить границу как свойство класса и удалять/повторно добавлять каждый раз. На данный момент я использую проверку bool.
Swift 3:
class CustomLayer: CALayer {
private var path: CGPath?
private var borderSet: Bool = false
init(maskLayer: CAShapeLayer) {
super.init()
self.path = maskLayer.path
self.frame = maskLayer.frame
self.bounds = maskLayer.bounds
self.mask = maskLayer
}
override func layoutSublayers() {
let newBorder = CAShapeLayer()
newBorder.lineWidth = 12
newBorder.path = self.path
newBorder.strokeColor = UIColor.black.cgColor
newBorder.fillColor = nil
if(!borderSet) {
self.addSublayer(newBorder)
self.borderSet = true
}
}
required override init(layer: Any) {
super.init(layer: layer)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}