Инвертировать маску CALayer, основанную на обводке (без заливки)

Уважаемое сообщество переполнения стека,

У меня есть проблема, касающаяся свойства маскиCAShapeLayer в iOS (Swift).

То, что я пытаюсь достичь, этоластик это стирает части слоя изображения, маскируя его. Проблема возникает, когда я пытаюсь ее перевернуть.

Я нашел несколько хороших ответов на инвертирование пути, но они были полезны только при использованиизаполненный дорожка. То, что я пытаюсь сделать, этоИнсульт путь и использовать перевернутый, чтобы замаскировать изображение. Ширина линии на обводке должна примерно30.0 так выглядит как ластик.

Я пробовал разные вещи. Моя текущая версия выглядит так:

СоздатьCAShapeLayer который держит путь ластикаУстановитьfill-color слоя вnilУстановитьstroke-color а такжеline widthДобавьте слой в качестве маски слоя изображения

Это работает нормально, но это только делает части изображения видимымикоторые в ходу, я хочу сделать этообратная, Я думал о черно-белой маске, но это не работает, потому что маска доставляется через альфа-канал.

У кого-нибудь есть идеи, как решить проблему?

 Christian 'fuzi' Orgler09 сент. 2016 г., 18:45
Я просто могу говорить за себя, но у меня есть путь, который обозначен чертой. И хочу обрезать круг (показано на скриншоте). Я хочу обрезать конец строки. (Я не хочу ретушировать сам путь) снимок экрана:d17oy1vhnax1f7.cloudfront.net/items/0b3A3D2H3B3v01221G1I/...
 Christian 'fuzi' Orgler15 сент. 2016 г., 17:53
Мне нужен ластик, который будет функционировать так, как я описал выше. Сам ластик не может иметь fillColor. Возможно, у вас может быть невидимый слой, у которого есть fillColor, который маскирует слой. Не уверен, попробую.
 Neil Galiaskarov09 сент. 2016 г., 18:38
Можете ли вы также добавить любые фотографии, которые описывают то, что вы хотите достичь?
 Marcus13 сент. 2016 г., 23:29
Стремлюсь помочь, но я был бы признателен, если бы вы могли уточнить - вы ищете способ создания ластика любыми возможными способами или важно, чтобы вы реализовали ластик так, как вы обрисовали в общих чертах?

Ответы на вопрос(1)

Решение Вопроса

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

@interface ShapeLayer : CALayer

@property(nonatomic) CGPathRef path;
@property(nonatomic) CGColorRef fillColor;
@property(nonatomic) CGColorRef strokeColor;
@property(nonatomic) CGFloat lineWidth;

@end

@implementation ShapeLayer

@dynamic path;
@dynamic fillColor;
@dynamic strokeColor;
@dynamic lineWidth;

- (void)drawInContext:(CGContextRef)inContext {
    CGContextSetGrayFillColor(inContext, 0.0, 1.0);
    CGContextFillRect(inContext, self.bounds);
    CGContextSetBlendMode(inContext, kCGBlendModeSourceIn);
    if(self.strokeColor) {
        CGContextSetStrokeColorWithColor(inContext, self.strokeColor);
    }
    if(self.fillColor) {
        CGContextSetFillColorWithColor(inContext, self.fillColor);
    }
    CGContextSetLineWidth(inContext, self.lineWidth);
    CGContextAddPath(inContext, self.path);
    CGContextDrawPath(inContext, kCGPathFillStroke);
}

@end

Создание слоя с прозрачным путем:

ShapeLayer *theLayer = [ShapeLayer layer];

theLayer.path = ...;
theLayer.strokeColor = [UIColor clearColor].CGColor;
theLayer.fillColor = [UIColor colorWithWhite:0.8 alpha:0.5];
theLayer.lineWith = 3.0;
theLayer.opaque = NO; // Important, otherwise you will get a black rectangle

Я использовал этот код для рисования полупрозрачного круга с прозрачной рамкой на зеленом фоне:

Редактировать: Вот соответствующий код для слоя в Swift:

public class ShapeLayer: CALayer {
    @NSManaged var path : CGPath?
    @NSManaged var fillColor : CGColor?
    @NSManaged var strokeColor : CGColor?
    @NSManaged var lineWidth : CGFloat

    override class func defaultValue(forKey inKey: String) -> Any? {
        return inKey == "lineWidth" ? 1.0 : super.defaultValue(forKey: inKey)
    }

    override class func needsDisplay(forKey inKey: String) -> Bool {
        return inKey == "path" || inKey == "fillColor" || inKey == "strokeColor" || inKey == "lineWidth" || super.needsDisplay(forKey: inKey)
    }

    override public func draw(in inContext: CGContext) {
        inContext.setFillColor(gray: 0.0, alpha: 1.0)
        inContext.fill(self.bounds)
        inContext.setBlendMode(.sourceIn)
        if let strokeColor = self.strokeColor {
            inContext.setStrokeColor(strokeColor)
        }
        if let fillColor = self.fillColor {
            inContext.setFillColor(fillColor)
        }
        inContext.setLineWidth(self.lineWidth)
        inContext.addPath(self.path!)
        inContext.drawPath(using: .fillStroke)
    }
}

Заметка: Пометив свойства с@NSManaged Вы можете легко сделать свойства анимируемыми, реализуяneedsDisplay(forKey inKey:) в Свифте илиneedsDisplayForKey: в цель C, соответственно. Я адаптировал код Swift соответственно.

Но даже если вам не нужны анимации, лучше пометить свойства@NSManagedпотому что QuartzCore делает копии слоев, а также должен копировать все свойства с ним.@NSManaged в Swift является аналогом@dynamic в цели C, потому что это позволяет избежать создания свойства реализации. ВместоCALayer получает и устанавливает значения свойств сvalue(forKey:) а такжеsetValue(_:forKey:)соответственно.

Ваш ответ на вопрос