Маска Core CGImage не влияет на

То, что я в основном пытаюсь сделать, это иметь текстовую метку "вырезать" текстовое отверстие в представлении. Я пробовал использовать self.mask = uiLabel, но они отказались правильно позиционировать текст, поэтому я подхожу к нему через Core Graphics.

Здесь код, который не работает (в draw(_ rect: CGRect)):

    let context = (UIGraphicsGetCurrentContext())!

    // Set mask background color
    context.setFillColor(UIColor.black.cgColor)
    context.fill(rect)

    context.saveGState()


    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center

    let attributes = [
        NSParagraphStyleAttributeName: paragraphStyle,
        NSFontAttributeName: UIFont.systemFont(ofSize: 16, weight: UIFontWeightMedium),
        NSForegroundColorAttributeName: UIColor.white
    ]

    let string = NSString(string: "LOGIN")

    // This wouldn't vertically align so we calculate the string size and create a new rect in which it is vertically aligned
    let size = string.size(attributes: attributes)
    let position = CGRect(
        x: rect.origin.x,
        y: rect.origin.y + (rect.size.height - size.height) / 2,
        width: rect.size.width,
        height: size.height
    )

    context.translateBy(x: 0, y: rect.size.height)
    context.scaleBy(x: 1, y: -1)
    string.draw(
        in: position,
        withAttributes: attributes
    )

    let mask = (context.makeImage())!

    context.restoreGState()

    // Redraw with created mask
    context.clear(rect)

    context.saveGState()
    // !!!! Below line is the problem
    context.clip(to: rect, mask: mask)
    context.restoreGState()

По сути, я успешно создал код для создания переменной CGImage (mask), которая является маской, которую я хочу применить ко всему изображению.

Отмечаемая строка при замене на context.draw(mask, in: rect) (для просмотра маски) отображается правильно. Маска показывает (правильно) как:

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

Однако, как только я пытаюсь применить эту маску (используя context.clip(to: rect, mask: mask)), ничего не происходит!. Фактический результат:

Ничего не меняется

Желаемый результат:

Желаемый результат

но по какой-то причине маска неправильно применяется.


Этот код кажется, что он должен работать, поскольку я читал документы снова и снова. Я также попытался создать маску в отдельном CGContext, который не работал. Также, когда я попытался преобразовать CGImage (mask) в CGColorSpaceCreateDeviceGray() с помощью .copy(colorSpace:), он вернул nil. Я был на этом в течение двух дней, поэтому любая помощь приветствуется

Ответы

Ответ 1

Если вы хотите, чтобы метка имела полностью прозрачный текст, вы можете использовать режимы наложения вместо масок.

public class KnockoutLabel: UILabel {
    public override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()!
        context.setBlendMode(.clear)

        self.drawText(in: rect)
    }
}

Обязательно установите isOpaque на false, хотя; по умолчанию представление предполагает, что оно непрозрачно, поскольку вы используете непрозрачный цвет фона.

Ответ 2

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

Код, поместите его внутри draw (_ rect: CGRect):

    //// General Declarations
    let context = UIGraphicsGetCurrentContext()

    //// Color Declarations - just to make a gradient same as your button have
    let gradientColor = UIColor(red: 0.220, green: 0.220, blue: 0.223, alpha: 1.000)
    let gradientColor2 = UIColor(red: 0.718, green: 0.666, blue: 0.681, alpha: 1.000)
    let gradientColor3 = UIColor(red: 0.401, green: 0.365, blue: 0.365, alpha: 1.000)

    //// Gradient Declarations
    let gradient = CGGradient(colorsSpace: nil, colors: [gradientColor.cgColor, gradientColor3.cgColor, gradientColor2.cgColor] as CFArray, locations: [0, 0.55, 1])!


    //// Subframes
    let group: CGRect = CGRect(x: rect.minX, y: rect.minY, width: rect.width, height: rect.height)


    //// Group
    context.saveGState()
    context.beginTransparencyLayer(auxiliaryInfo: nil)


    //// Rectangle Drawing
    let rectanglePath = UIBezierPath(roundedRect: group, cornerRadius: 5)
    context.saveGState()
    rectanglePath.addClip()
    let rectangleRotatedPath = UIBezierPath()
    rectangleRotatedPath.append(rectanglePath)
    var rectangleTransform = CGAffineTransform(rotationAngle: -99 * -CGFloat.pi/180)
    rectangleRotatedPath.apply(rectangleTransform)
    let rectangleBounds = rectangleRotatedPath.cgPath.boundingBoxOfPath
    rectangleTransform = rectangleTransform.inverted()
    context.drawLinearGradient(gradient,
                               start: CGPoint(x: rectangleBounds.minX, y: rectangleBounds.midY).applying(rectangleTransform),
                               end: CGPoint(x: rectangleBounds.maxX, y: rectangleBounds.midY).applying(rectangleTransform),
                               options: [])
    context.restoreGState()


    //// Text Drawing
    context.saveGState()
    context.setBlendMode(.destinationOut)

    let textRect = group
    let textTextContent = "LOGIN"
    let textStyle = NSMutableParagraphStyle()
    textStyle.alignment = .center
    let textFontAttributes = [
        NSFontAttributeName: UIFont.systemFont(ofSize: 16, weight: UIFontWeightBold),
        NSForegroundColorAttributeName: UIColor.black,
        NSParagraphStyleAttributeName: textStyle,
        ]

    let textTextHeight: CGFloat = textTextContent.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).height
    context.saveGState()
    context.clip(to: textRect)
    textTextContent.draw(in: CGRect(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight) / 2, width: textRect.width, height: textTextHeight), withAttributes: textFontAttributes)
    context.restoreGState()

    context.restoreGState()


    context.endTransparencyLayer()
    context.restoreGState()

Результаты:

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

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

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