遮罩UIView/UIImageView以剪切透明文本

13

如何掩盖UIView或UIImageView,使文本从其中切出?

我搜索了很多,发现许多人都遇到了同样的问题。最令人烦恼的是,我总是尝试反转截图视图的alpha通道来获得所需的结果。

我想要的效果看起来像这样:

输入图像描述

2个回答

13

这是定制口罩标签。

import UIKit
final class MaskLabel: UILabel {

// MARK: - IBInspectoable
@IBInspectable var cornerRadius: CGFloat {
    get { return self.layer.cornerRadius }
    set { self.layer.cornerRadius = newValue }
}

@IBInspectable var borderWidth: CGFloat {
    get { return self.layer.cornerRadius }
    set { self.layer.borderWidth = newValue }
}

@IBInspectable var borderColor: UIColor {
    get { return UIColor(cgColor: self.layer.borderColor ?? UIColor.clear.cgColor) }
    set { self.layer.borderColor = newValue.cgColor }
}

@IBInspectable var insetTop: CGFloat {
    get { return self.textInsets.top }
    set { self.textInsets.top = newValue }
}

@IBInspectable var insetLeft: CGFloat {
    get { return self.textInsets.left }
    set { self.textInsets.left = newValue }
}

@IBInspectable var insetBottom: CGFloat {
    get { return self.textInsets.bottom }
    set { self.textInsets.bottom = newValue }
}

@IBInspectable var insetRight: CGFloat {
    get { return self.textInsets.right }
    set { self.textInsets.right = newValue }
}



// MARK: - Value
// MARK: Public
private var textInsets = UIEdgeInsets.zero
private var originalBackgroundColor: UIColor? = nil



// MARK: - Initializer
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    setLabelUI()
}

override init(frame: CGRect) {
    super.init(frame: frame)

    setLabelUI()
}

override func prepareForInterfaceBuilder() {
    setLabelUI()
}


// MARK: - Draw
override func drawText(in rect: CGRect) {
    super.drawText(in: UIEdgeInsetsInsetRect(rect, textInsets))
    guard let context = UIGraphicsGetCurrentContext() else { return }

    context.saveGState()
    context.setBlendMode(.clear)

    originalBackgroundColor?.setFill()
    UIRectFill(rect)

    super.drawText(in: rect)
    context.restoreGState()
}


// MARK: - Function
// MARK: Private
private func setLabelUI() {
    // cache (Before masking the label, the background color must be clear. So we have to cache it)
    originalBackgroundColor = backgroundColor
    backgroundColor = .clear

    layer.cornerRadius = cornerRadius
    layer.borderWidth  = borderWidth
    layer.borderColor  = borderColor.cgColor
}
}

输入图像描述 输入图像描述

这就是结果。 输入图片描述


我认为你不需要去操作图形状态,对吧?我相信UIKit在调用你的绘制代码前后会隐式地保存和恢复状态。 - CIFilter

7

我遇到的主要问题是我的理解。我们不必采取有色视图并尝试在其中制作透明孔,而是可以反过来叠加它。

因此,我们将有色背景放在后面,然后是前面的带有蒙版的图像,只显示文本部分。如果您正在使用iOS 8+,那么实际上这非常简单,只需使用UIView的maskView属性即可。

因此,在Swift中,它可能看起来像这样:

    let coloredBackground = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
    coloredBackground.backgroundColor = UIColor.greenColor()

    let imageView = UIImageView(frame: coloredBackground.bounds)
    imageView.image = UIImage(named: "myImage")
    coloredBackground.addSubview(imageView)

    let label = UILabel(frame: coloredBackground.bounds)
    label.text = "stackoverflow"
    coloredBackground.addSubview(label)

    imageView.maskView = label

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接