Как нарисовать границу CALayer вокруг своей маски?

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

Может ли кто-нибудь помочь мне решить эту проблему?

5 Solutions collect form web for “Как нарисовать границу CALayer вокруг своей маски?”

Некоторые предложения:

  • Используйте непрозрачную тень вместо границы (у вас будет размытый эффект).
  • Создайте еще один слой, установите его цвет фона с цветом, который вы хотите для своей границы, замаскируйте его маской, которая немного больше, чем та, которую у вас уже есть, чтобы имитировать ширину границы и поместить ее по центру вашего слоя (возможно, она не работает с каждой формой ).
  • Сделайте морфологическую операцию на изображении маски для вычисления границы, например, с vImageDilate семейства функций vImageDilate (более сложным и может столкнуться с проблемами производительности).
  • Если вы знаете форму и ее можно описать математически, нарисуйте ее и погладьте явным образом с помощью функций Core Graphics.
  • Или, в том же случае (форма, известная математически), используйте CAShapeLayer для рисования границы.

Рассмотрим этот пример кода:

 - (void)drawRect:(CGRect)rect { CAShapeLayer *maskLayer = [CAShapeLayer layer]; //Modify to your needs CGFloat maskInsetWidth = 5.0f; CGFloat maskInsetHeight = 5.0f; CGFloat maskCornerRadius = 5.0f; CGFloat borderWidth = 2.0f; UIColor *borderColor = [UIColor blackColor]; CGRect insetRect = CGRectInset(self.bounds, maskInsetWidth, maskInsetHeight); insetRect.size.width = MAX(insetRect.size.width, 0); insetRect.size.height = MAX(insetRect.size.height, 0); CGPathRef path = [UIBezierPath bezierPathWithRoundedRect:insetRect cornerRadius:maskCornerRadius].CGPath; if (borderWidth > 0.0f && borderColor != nil) { CAShapeLayer *borderLayer = [CAShapeLayer layer]; [borderLayer setPath:path]; [borderLayer setLineWidth:borderWidth * 2.0f]; [borderLayer setStrokeColor:borderColor.CGColor]; [borderLayer setFillColor:[UIColor clearColor].CGColor]; borderLayer.frame = self.bounds; [self.layer addSublayer:borderLayer]; } [maskLayer setPath:path]; [maskLayer setFillRule:kCAFillRuleEvenOdd]; maskLayer.frame = self.bounds; [self.layer setMask:maskLayer]; } 

В общем случае вы не можете легко установить границу вокруг маски. Это как просить оформить границу вокруг прозрачных пикселей изображения. Возможно, это может быть сделано с использованием фильтров изображений. В более конкретном случае, если вы используете простой CAShapeLayer, вот пример кода, который делает это:

 [CATransaction begin]; [CATransaction setDisableActions:YES]; CALayer *hostLayer = [CALayer layer]; hostLayer.backgroundColor = [NSColor blackColor].CGColor; hostLayer.speed = 0.0; hostLayer.timeOffset = 0.0; CALayer *maskedLayer = [CALayer layer]; maskedLayer.backgroundColor = [NSColor redColor].CGColor; maskedLayer.position = CGPointMake(200, 200); maskedLayer.bounds = CGRectMake(0, 0, 200, 200); CAShapeLayer *mask = [CAShapeLayer layer]; mask.fillColor = [NSColor whiteColor].CGColor; mask.position = CGPointMake(100, 100); mask.bounds = CGRectMake(0, 0, 200, 200); CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, 100, 100); for (int i=0; i<20; i++) { double x = arc4random_uniform(2000) / 10.0; double y = arc4random_uniform(2000) / 10.0; CGPathAddLineToPoint(path, NULL, x, y); } CGPathCloseSubpath(path); mask.path = path; CGPathRelease(path); maskedLayer.mask = mask; CAShapeLayer *maskCopy = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:mask]]; maskCopy.fillColor = NULL; maskCopy.strokeColor = [NSColor yellowColor].CGColor; maskCopy.lineWidth = 4; maskCopy.position = maskedLayer.position; // Alternately, don't set the position and add the copy as a sublayer // maskedLayer.sublayers = @[maskCopy]; hostLayer.sublayers = @[maskedLayer,maskCopy]; _contentView.layer = hostLayer; _contentView.wantsLayer = YES; [CATransaction commit]; 

Он в основном создает произвольный путь и устанавливает его как маску. Затем он берет копию этого слоя, чтобы погладить путь. Возможно, вам придется подстроить все, чтобы получить точный эффект, который вы ищете.

Свифт 2 Вернера отвечает

введите описание изображения здесь

  //setup MASK imageView.layer.mask = nil; let cornerRadius = self.imageView.bounds.height * 0.5 let maskPath = UIBezierPath(roundedRect: self.imageView.bounds, byRoundingCorners: [.TopLeft, .BottomRight], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)) let maskLayer = CAShapeLayer() maskLayer.frame = self.bounds; maskLayer.path = maskPath.CGPath self.imageView.layer.mask = maskLayer //setup Border for Mask let maskInsetWidth :CGFloat = 0.0 let maskInsetHeight :CGFloat = 0.0 let borderWidth: CGFloat = self.imageView.bounds.width * 0.05 let borderColor = UIColor.redColor() let insetRect = CGRectInset(imageView.bounds, maskInsetWidth, maskInsetHeight) let path = UIBezierPath(roundedRect: insetRect, byRoundingCorners: [.TopLeft, .BottomRight], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)).CGPath let borderLayer = CAShapeLayer() borderLayer.path = path borderLayer.lineWidth = borderWidth * 2.0 borderLayer.strokeColor = borderColor.CGColor borderLayer.fillColor = UIColor.clearColor().CGColor borderLayer.frame = imageView.bounds imageView.layer.addSublayer(borderLayer) 

Если вы CALayer , вы можете создать его с помощью маски, которую вы хотите, а также переопределить layoutSubLayers чтобы включить 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") } } 
  • Создание настраиваемой панели выполнения с изображениями
  • Interesting Posts
    PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.