什么是镂空效果,下图就是一个镂空效果的文字:

从图可知,文字是透明的,可以看到下面的图片内容,而UILabel其它部分是白色背景。

使用Quartz 2D绘制镂空效果,大体思路如下:

  1. 实现一个UILabel的子类(这个不是必须的,这样做的目的是为了利用UILabel自身的文字绘制功能方便的绘制出文字,你也可以采用CoreText绘制文字)
  2. 初始化当前视图时确保backgroundColor==.clear(这样做是实现落空文字的关键,因为文字部分必须是透明的)
  3. 利用UILabel自身的绘制方法,绘制出一个文字蒙版(注意:绘制的原图必须是透明底,白色文字(确保textColor为.white)。这样才能正确的创建一个我们需要的文字蒙版)
  4. 调用clip(to rect: CGRect, mask: CGImage)来裁剪当前视图的上下文,mask就是3中创建的蒙版(在此之前需要转换上下文的坐标系)
  5. 填充上下文背景色

附上代码:

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.

Quartz 2D实现文字镂空效果的更多相关文章

  1. CSS 奇技淫巧 | 妙用混合模式实现文字镂空波浪效果

    本文将介绍一个小技巧,通过混合模式 mix-blend-mode 巧妙的实现文字的镂空波浪效果. 起因 一日,一群友私聊问我.如何使用 CSS 实现下述效果,一个文字的波浪效果: 我当时想都没想,就回 ...

  2. Quartz 2D在ios中的使用简述一:坐标体系

    Quartz 2D是一个二维图形绘制引擎,支持iOS环境和Mac OS X环境,官方文档:Quartz 2D Programming Guide. 一.坐标体系 这样的坐标体系就导致我们使用Quart ...

  3. iOS 2D绘图 (Quartz 2D) 概述

    本篇博客原文地址:http://blog.csdn.net/hello_hwc?viewmode=list 由于自己的项目需要,从网络上下载了许多关于绘制图形的demo,只是用在自己的项目中,很多地方 ...

  4. iOS 2D绘图详解(Quartz 2D)之概述

    前言:最近在研究自定义控件,由于想要彻底的定制控件的视图还是要继承UIView,虽然对CALayer及其子类很熟练,但是对Quartz 2D这个强大的框架仍然概念模棱两可.于是,决定学习下,暂定7篇文 ...

  5. iOS基础 - Quartz 2D绘图

    一.Quartz 2D Quartz 2D是一个二维图形绘制引擎,支持iOS环境和Mac OS X环境. Quartz 2D以PDF的规范为基础的图形库,用来绘制二维文字和图形,允许相同的绘图指令在任 ...

  6. iOS - Quartz 2D 二维绘图

    1.Quartz 2D 简介 Quartz 2D 属于 Core Graphics(所以大多数相关方法的都是以 CG 开头),是 iOS/Mac OSX 提供的在内核之上的强大的 2D 绘图引擎,并且 ...

  7. Quartz 2D中CGContextSaveGState与UIGraphicsPushContext

    CGContextRef: An opaque type that represents a Quartz 2D drawing environment. Graphics Context是图形上下文 ...

  8. 1.0 Quartz 2D 简介

    本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人 “简书”   Quartz2D须知:   (1)Quartz 2D是苹果官方的二维绘图引擎,同时支持 ...

  9. Quartz 2D绘制简单图形

    在Quartz 2D中,绘图是通过图形上下文进行绘制的,以下绘制几个简单的图形 首先先创建一个QuartzView.swift文件继承自UIView,然后实现drawRect方法: import UI ...

  10. Quartz 2d绘图

    今天看了一下Quartz 2D绘图,我只想说:不要把绘图和动画那些东西当做一个很复杂的东西,其实只要你认真看还是可以理解的.他们并不难.啰嗦了几句,现在直接进入正题: 前提是我们必须新建一个singl ...

随机推荐

  1. 线程基础知识05 synchronized类锁和对象锁演示

    1 简介 synchronized在方法内,同步代码块,传入对象,使用的是对象锁,传入class对象,使用的是类锁 作用于普通方法,也是对象锁,当前对象 作用于静态方法,是类锁 2 同步方法示例 2. ...

  2. 【开发宝典】Java并发系列教程(四)

    作者:京东零售 刘跃明 Monitor概念 Java对象的内存布局 对象除了我们自定义的一些属性外,还有其它数据,在内存中可以分为三个区域:对象头.实例数据.对齐填充,这三个区域组成起来才是一个完整的 ...

  3. LeetCode HOT 100:乘积最大子数组(动态规划)

    题目:152. 乘积最大子数组 题目描述: 给你一个整数数组,在该数组的所有子数组中,找到一个子数组中所有元素相乘积最大,返回这个最大的积.子数组就是一个数组中,由一个或几个下标连续的元素,组成的小数 ...

  4. JZOJ 4270.【NOIP2015模拟10.27】魔道研究

    魔道研究 题面 思路 简单的想,就是在 \(T\) 个可重集合每个中选出 \(k\) 个最大的数组成新的可重集合,其中 \(k\) 为其编号 然后在新的集合中选前 \(n\) 大的数,求其和 考虑开 ...

  5. 为了安装alien,我更新了yum源,结果还是没装上

    前几天把自己的thinkpad E430C从win7系统装成了centos7,看过<周末折腾了两天,踩了无数个坑,终于把win7装成了centos7>的小伙伴都知道,为了把win7装成ce ...

  6. 钓鱼攻击之:OFFICE 宏后门文件钓鱼

    钓鱼攻击之:OFFICE 宏后门文件钓鱼 目录 钓鱼攻击之:OFFICE 宏后门文件钓鱼 1 宏病毒介绍 1.1 Word 宏 1.2 Excel 4.0宏 2 生成 Word 宏后门 3 利用DOC ...

  7. 在Github的fork项目中切换分支来提交PR

    在Github的fork项目中切换分支来提交PR 查看远程所有分支 git branch不带参数,列出本地已经存在的分支,并且在当前分支的前面用*标记,加上-a参数可以查看所有分支列表,包括本地和远程 ...

  8. 【6】java之数组的定义和使用

    一.数组的定义与使用 1.1 数组的基本概念 数组指的就是一组相关变量的集合. 数组的定义: 声明并开辟数组 数据类型 数组名称 [] = new 数据类型[长度]: 数据类型 [] 数组名称 = n ...

  9. KCL 语言和 YAML 字符串的区别是什么?一文完全解答

    什么是 YAML YAML 是一种数据序列化语言,通常用于编写配置文件.YAML 代表另一种标记语言或YAML 不是标记语言(递归首字母缩写词),YAML 通常用于数据,而不是文档.YAML 还是一种 ...

  10. C# DevExpress GridControl下动态创建列的方法

    这里是把在表格中创建控件的方法封装成一个类,然后在创建列的时候实例化"创建控件"的方法 1.在列中使用一些按钮 1 using Common; 2 using DevExpress ...