什么是镂空效果,下图就是一个镂空效果的文字:
从图可知,文字是透明的,可以看到下面的图片内容,而UILabel其它部分是白色背景。
使用Quartz 2D绘制镂空效果,大体思路如下:
附上代码:
class PiercedLabel: UILabel {
override var textColor: UIColor!{
didSet {
if textColor != .white {
textColor = .white // 要实现一个镂空的文字,这里的颜色必须设置成白色
}
}
}
override var backgroundColor: UIColor?{
didSet {
// backgroundColor要确保始终为.clear(透明色),这样才可以实现一个镂空效果
guard let color = backgroundColor else {
backgroundColor = .clear
// 当设置backgroundColor == nil时,我们默认背景为白色
bgColor = .white
return
}
if color != .clear {
bgColor = color // 保留设置的背景色,以便后续绘制背景
backgroundColor = .clear
}
}
}
// 用于绘制背景色
private var bgColor: UIColor!
init() {
super.init(frame: .zero)
config()
}
override init(frame: CGRect) {
super.init(frame: frame)
config()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
config()
}
private func config(){
textColor = .white
bgColor = .white
backgroundColor = .clear
}
override func draw(\_ rect: CGRect) {
// 创建一个用于绘制图片的图形上下文,这里必须是透明的,以便创建一个文字蒙版
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
guard let maskContext = UIGraphicsGetCurrentContext() else {
return
}
// 注意:此时的maskContext并不是当前draw方法提供的上下文,而是我们调用UIGraphicsBeginImageContextWithOptions
// 构建的新的图形上下文,我们在这个上下文中绘制文字蒙版
// 绘制文字到maskContext上下文中
super.draw(rect)
// 获取maskContext上下文的bitmap图片
guard let textImg = maskContext.makeImage() else {
UIGraphicsEndImageContext() // 结束maskContext上下文
return
}
UIGraphicsEndImageContext() // 结束maskContext上下文
// 注意:此时的textImg并不能作为文字蒙版,我们需要通过如下方法创建一个蒙版图片
// 创建蒙版图
guard let maskImg = CGImage(maskWidth: textImg.width,
height: textImg.height,
bitsPerComponent: textImg.bitsPerComponent,
bitsPerPixel: textImg.bitsPerPixel,
bytesPerRow: textImg.bytesPerRow,
provider: textImg.dataProvider!,
decode: textImg.decode,
shouldInterpolate: textImg.shouldInterpolate) else {
return
}
// 获取当前draw方法提供的上下文,我们需要将内容绘制到这里
guard let ctx = UIGraphicsGetCurrentContext() else {
return
}
// 先保存当前上下文状态
ctx.saveGState()
ctx.clear(rect)
// 调整当前上下文的坐标系,因为ctx.draw绘制的坐标系是按照左下角问原点的
// 因此我们需要将坐标系改成左上角,这样绘制的结果才是正确的,否则文字是颠倒的
ctx.translateBy(x: 0, y: rect.height)
ctx.scaleBy(x: 1, y: -1)
// 使用蒙版进行裁剪,它会将ctx上下文rect区域的文字部分裁减掉
ctx.clip(to: rect, mask: maskImg)
// 绘制背景色(注意:被裁减掉的部分不会填充,这样就形成了一个镂空的效果了)
// 因为ctx上下文是根据当前视图的backgroundColor创建的,而backgroundColor == .clear,是一个透明的
// 所以ctx就是一个含有透明层的上下文,被裁剪掉的文字部分就是一个透明的了
// 这也是为什么要确保backgroundColor == .clear了
bgColor.setFill()
ctx.fill(rect)
}
}
代码中的注释已经写的很详细了,具体的解释就不详细描述了
下面是绘制原文本和蒙版的对照图:
原文本:是一个透明底,白色文字
蒙版:是一个透明底,黑色文字
有人会想到,那我们可不可以直接用原文本图片作为蒙版呢?可以,但是那将不是我们想要的效果,它将会是下面的效果:
背景色成为了文字的颜色,而背景色却成为了透明的。这正与我们想要的效果相反。
因此我们必须通过CGImageMaskCreate创建一个蒙版图片。
关于ImageMask的解释可以查看苹果官方文档
截取部分说明:
Image masks must be 1, 2, 4, or 8 bits per component. For a 1-bit mask, a sample value of 1
specifies sections of the mask that are masked out; these sections block the current fill color. A sample value of 0
specifies sections of the mask that are not masked out; these sections show the current fill color of the graphics state when the mask is painted. You can think of the sample values as an inverse alpha. That is, a value of 1
is transparent and 0
is opaque.
手机扫一扫
移动阅读更方便
你可能感兴趣的文章