如何在 Swift 中应用反文字掩码?

How to apply an inverse text mask in Swift?

我正在尝试以编程方式创建一个带有透明文本的图层。我尝试的一切似乎都不起作用。我的最终目标是在文本上创建一个内部阴影。

我想要文本而不是下面代码中的圆圈。

let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
view.backgroundColor = .white

// MASK
let blackSquare = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
blackSquare.backgroundColor = .black
view.addSubview(blackSquare)

let maskLayer = CAShapeLayer()

// Create a path with the rectangle in it.
let path = CGMutablePath()
path.addArc(center: CGPoint(x: 100, y: 100), radius: 50, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: false)
path.addRect(CGRect(x: 0, y: 0, width: blackSquare.frame.width, height: blackSquare.frame.height))
maskLayer.backgroundColor = UIColor.black.cgColor

maskLayer.path = path;
maskLayer.fillRule = kCAFillRuleEvenOdd

blackSquare.layer.mask = maskLayer

maskLayer.masksToBounds = false
maskLayer.shadowRadius = 4
maskLayer.shadowOpacity = 0.5
maskLayer.shadowOffset = CGSize(width: 5, height: 5)

view.addSubview(blackSquare)

我也可以使用文本作为遮罩,但无法反转遮罩。感谢任何帮助。

编辑:

我根据 Josh 的建议,根据 Rob 的回答弄明白了。这是我的游乐场代码。

import Foundation
import UIKit
import PlaygroundSupport

// view
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
view.backgroundColor = .black

// button
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
button.setTitle("120", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont(name: "AvenirNextCondensed-UltraLight", size: 200)

view.addSubview(button)

addInnerShadow(button: button)

func addInnerShadow(button: UIButton) {

// text
let text = button.titleLabel!.text!

// get context
UIGraphicsBeginImageContextWithOptions(button.bounds.size, true, 0)
let context = UIGraphicsGetCurrentContext()

context?.scaleBy(x: 1, y: -1)
context?.translateBy(x: 0, y: -button.bounds.size.height)

let font = button.titleLabel!.font!

// draw the text
let attributes = [
    NSAttributedStringKey.font: font,
    NSAttributedStringKey.foregroundColor: UIColor.white
]

let size = text.size(withAttributes: attributes)
let point = CGPoint(x: (button.bounds.size.width - size.width) / 2.0, y: (button.bounds.size.height - size.height) / 2.0)
text.draw(at: point, withAttributes: attributes)

// capture the image and end context
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

// create image mask
let cgimage = image?.cgImage!
let bytesPerRow = cgimage?.bytesPerRow
let dataProvider = cgimage?.dataProvider!
let bitsPerPixel = cgimage?.bitsPerPixel
let width = cgimage?.width
let height = cgimage?.height
let bitsPerComponent = cgimage?.bitsPerComponent
let mask = CGImage(maskWidth: width!, height: height!, bitsPerComponent: bitsPerComponent!, bitsPerPixel: bitsPerPixel!, bytesPerRow: bytesPerRow!, provider: dataProvider!, decode: nil, shouldInterpolate: false)

// create background
UIGraphicsBeginImageContextWithOptions(button.bounds.size, false, 0)
UIGraphicsGetCurrentContext()!.clip(to: button.bounds, mask: mask!)
view.backgroundColor!.setFill()
UIBezierPath(rect: button.bounds).fill()
let background = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

let backgroundView = UIImageView(image: background)

// add shadows
backgroundView.layer.shadowOffset = CGSize(width: 2, height: 2)
backgroundView.layer.shadowRadius = 2
backgroundView.layer.shadowOpacity = 0.75

button.addSubview(backgroundView)

}

PlaygroundPage.current.liveView = view

虽然不完全相同,但请参考回答类似问题的答案:

How do I style a button to have transparent text?

这至少能让你入门...

偶然发现了一个可能的 solution,我已将其更新为正确的语法:

func mask(withRect rect: CGRect, inverse: Bool = false) {
    let path = UIBezierPath(rect: rect)
    let maskLayer = CAShapeLayer()

    if inverse {
        path.append(UIBezierPath(rect: self.view.bounds))
        maskLayer.fillRule = kCAFillRuleEvenOdd
    }

    maskLayer.path = path.cgPath

    self.view.layer.mask = maskLayer
}

您显然需要挑选零件,看看它是否适合您。