版本记录
版本号 | 时间 |
---|---|
V1.0 | 2019.02.01 星期五 |
前言
quartz
是一个通用的术语,用于描述在iOS
和MAC OS X
中整个媒体层用到的多种技术 包括图形、动画、音频、适配。Quart 2D
是一组二维绘图和渲染API
,Core Graphic
会使用到这组API
,Quartz Core
专指Core Animation
用到的动画相关的库、API
和类。CoreGraphics
是UIKit
下的主要绘图系统,频繁的用于绘制自定义视图。Core Graphics
是高度集成于UIView
和其他UIKit
部分的。Core Graphics
数据结构和函数可以通过前缀CG
来识别。在app中很多时候绘图等操作我们要利用CoreGraphic
框架,它能绘制字符串、图形、渐变色等等,是一个很强大的工具。感兴趣的可以看我另外几篇。
1. CoreGraphic框架解析(一)—— 基本概览
2. CoreGraphic框架解析(二)—— 基本使用
3. CoreGraphic框架解析(三)—— 类波浪线的实现
4. CoreGraphic框架解析(四)—— 基本架构补充
5. CoreGraphic框架解析 (五)—— 基于CoreGraphic的一个简单绘制示例 (一)
6. CoreGraphic框架解析 (六)—— 基于CoreGraphic的一个简单绘制示例 (二)
7. CoreGraphic框架解析 (七)—— 基于CoreGraphic的一个简单绘制示例 (三)
8. CoreGraphic框架解析 (八)—— 基于CoreGraphic的一个简单绘制示例 (四)
开始
首先看下写作环境
Swift 4.2, iOS 12, Xcode 10
在这个Core Graphics
教程中,您将创建样式(patterns)
,在Playgrounds
中对它们进行原型化,并强化一些概念,如基于路径的绘制。
在本教程中,您将使用Core Graphics
来完成名为Recall
的模式识别游戏。
打开已经下载好的工程并运行,如下所示:
Recall
从Left vs Right brain
应用程序中的游戏中获取灵感。 游戏的目标是为视图中的对象选择流行的方向。 一旦做出选择,就会显示一组新对象。 在比赛结束前你有五次尝试。
Recall
对四个象限中的图案对象进行分组。 入门应用中的每个象限都有一个label
。 文本表示方向,背景颜色表示填充颜色。
这个游戏现在相当平庸。
您的任务是使用新发现的Core Graphics
将其转换为下面的完成的应用程序:
看看Xcode中的项目。这些是主要文件:
- GameViewController.swift:控制游戏玩法并显示游戏视图。
- ResultViewController.swift:显示最终得分和重启游戏的按钮。
- PatternView.swift:显示游戏视图中其中一个象限的样式视图。
您将增强PatternView
以显示所需的模式。
对于初学者,您将在Playgrounds
中对新的和改进的PatternView
进行原型设计。这使您可以更快地迭代,同时了解Core Graphics
模式的细节。完成后,您将相关代码传输到Recall
启动项目。
在Xcode中,转到File ▸ New ▸ Playground…
,选择Single View
模板。单击Next
,将playground
命名为PatternView.playground
,然后单击Create
。您的playground
包含一个带有单个视图的视图控制器。
选择Editor ▸ Run Playground
以执行playground
。单击Show the Assistant Editor
以显示启动器视图。它显示了标志性的“Hello World!”
,结果:
在浏览下一节时,您将使用模式视图(pattern view)
替换起始视图。准备开始了吗?
Anatomy of a Pattern
在之前的Core Graphics
教程中,您已经了解了如何定义和绘制这样的路径:
上面的示例显示您使用颜色填充左侧的路径。 请记住,您还可以使用颜色描边路径。
使用Core Graphics
,您还可以使用模式(pattern)
描边或填充路径。 下面的示例显示填充路径的彩色图案:
您可以通过执行以下操作来设置模式:
- 1) 编写一个绘制单个模式单元格的方法。
- 2) 使用包含如何绘制和放置单个单元格的参数创建模式。
- 3) 定义模式将使用的颜色信息。
- 4) 使用您创建的模式绘制所需的路径。
现在,check out 一个略有不同的模式单元格和额外的填充。 细黑边框显示单元格的边界:
要在单元格的边界内绘制,请为模式单元格编写draw
方法。 Core Graphics
剪辑除界限之外的任何内容。 Core Graphics
还希望您每次都以完全相同的方式绘制图案单元格(pattern cell)
。
设置图案单元格时,draw
方法可以应用颜色。 这是一个彩色图案。 无色或掩蔽图案是在draw
方法之外应用填充颜色的图案。 这使您可以灵活地在有意义的地方设置图案颜色。
Core Graphics
重复调用draw
方法来设置模式。 模式创建参数定义模式的外观。 下面的示例显示了一个基本的重复模式,其中单元格彼此相邻排列:
配置模式时,可以指定模式单元格之间的间距:
您还可以应用变换来更改图案的外观。 下图显示了由模糊边框表示的空间内绘制的图案:
第一个显示未更改的模式。 在第二个中,您会看到translated
的模式。 第三个显示旋转的图案。 同样,图案单元周围的黑色边框突出了它的边界。
配置模式时,您有很多选项可用。 你将在下一节开始把所有这些放在一起。
Creating your First Pattern
在PatternView.playground
中的视图控制器类之前添加以下代码:
class PatternView: UIView {
override func draw(_ rect: CGRect) {
// 1
let context = UIGraphicsGetCurrentContext()!
// 2
UIColor.orange.setFill()
// 3
context.fill(rect)
}
}
这表示模式的自定义视图。 在这里,您重写draw(_ :)
以执行以下操作:
- 1) 获取视图的图形上下文。
- 2) 设置上下文的当前填充颜色。
- 3) 使用当前填充颜色填充整个上下文。
将图形上下文视为可以绘制的画布。 上下文包含将填充或描边路径的颜色等信息。 在使用上下文的颜色信息绘制路径之前,您可以在画布中绘制路径。
在MyViewController
内部,使用以下内容替换与label
相关的loadView()
中的代码:
let patternView = PatternView()
patternView.frame = CGRect(x: 10, y: 10, width: 200, height: 200)
view.addSubview(patternView)
这将创建模式视图的实例,设置其frame并将其添加到视图中。
按Shift + Command + Return
以运行playground
。 之前的label
已经消失,取而代之的是橙色子视图:
着色只是旅程的开始。 你知道还有更多来自哪里!
在PatternView
的顶部添加以下属性:
let drawPattern: CGPatternDrawPatternCallback = { _, context in
context.addArc(
center: CGPoint(x: 20, y: 20), radius: 10.0,
startAngle: 0, endAngle: CGFloat(2.0 * .pi),
clockwise: false)
context.setFillColor(UIColor.black.cgColor)
context.fillPath()
}
上面的代码在图形上下文中绘制一个圆形路径,并用黑色填充它。
这表示模式单元格的绘制方法,其类型为CGPatternDrawPatternCallback
。 该方法接受指向与模式关联的私有数据的指针。 您没有使用私有数据,因此使用了未命名的参数。 该方法还接受绘制模式单元格时使用的图形上下文。
将以下代码添加到draw(_:)
:
var callbacks = CGPatternCallbacks(
version: 0, drawPattern: drawPattern, releaseInfo: nil)
您为drawPattern
提供回调,releaseInfo
接受系统释放模式时调用的回调。 如果您在模式中使用私有数据,通常会设置一个release
回调函数。 由于您不在draw方法中使用私有数据,因此将nil
传递给此回调。
在回调分配后立即添加以下内容:
let pattern = CGPattern(
info: nil,
bounds: CGRect(x: 0, y: 0, width: 20, height: 20),
matrix: .identity,
xStep: 50,
yStep: 50,
tiling: .constantSpacing,
isColored: true,
callbacks: &callbacks)
这会创建一个模式对象。 在上面的代码中,您传递以下参数:
-
info
:指向要在模式回调中使用的任何私有数据的指针。 你传递的是nil,因为你没有使用任何。 -
bounds
:Pattern cell
的边界框。 -
matrix
:表示要应用的变换的矩阵。 您传递了单位矩阵,因为您没有应用任何变换。 -
xStep
:模式单元格之间的水平间距。 -
yStep
:图案单元格之间的垂直间距。 -
tiling
:更改为用户空间单位和设备像素之间的差异。 -
isColored
:图案单元格绘制方法是否应用颜色。 您将此设置为true
,因为您的绘制方法设置了颜色。 -
callbacks
:指向保存模式回调的结构的指针。
在pattern
分配后立即添加以下代码:
var alpha : CGFloat = 1.0
context.setFillPattern(pattern!, colorComponents: &alpha)
context.fill(rect)
上面的代码设置了图形上下文的填充模式。 对于彩色图案,还必须传入alpha
值以指定图案不透明度。 图案绘制方法提供颜色。 最后,代码使用模式绘制视图的frame区域。
按Shift + Command + Return
运行playground
。 您的模式没有显示出来。 奇怪。 这是怎么回事?
您需要为Core Graphics
提供有关图案颜色空间的信息,以便它知道如何处理图案颜色。
在alpha
声明上面添加以下内容:
// 1
let patternSpace = CGColorSpace(patternBaseSpace: nil)!
// 2
context.setFillColorSpace(patternSpace)
这是代码的作用:
- 1) 创建图案颜色空间。 对于彩色图案,基本空间参数应为
nil
。 这会将着色委托给您的图案单元格绘制方法。 - 2) 将填充颜色空间设置为定义的图案颜色空间。
运行playground
。 好的! 你现在应该看到一个圆形的黑色图案:
如何更好地配置模式?
Configuring a Pattern
在您的playground
中,更改设置pattern
的间距参数,如下所示:
xStep: 30,
yStep: 30,
运行playground
,请注意,圆点似乎彼此更接近:
这是有意义的,因为你缩小了模式单元格之间的步长。
现在,更改间距参数,如下所示:
xStep: 20,
yStep: 20,
运行playground
,你的圆圈变成了四分之一:
要了解原因,请注意您的绘制方法返回一个半径为10的圆,其中心位于(20,20)
。 模式的水平和垂直位移为20,单元格的边界框在原点(0,0)
处为20✕20
。 这导致重复的四分之一圆从右下边缘开始。
更改绘制圆的drawPattern
代码,如下所示:
context.addArc(
center: CGPoint(x: 10, y: 10), radius: 10.0,
startAngle: 0, endAngle: CGFloat(2.0 * .pi),
clockwise: false)
您已将中心点更改为(10,10)
而不是(20,20)
。
运行playground
,由于圆圈中心的移动,你回到了整个圈子:
图案单元格边界也与圆圈完美匹配,导致每个单元格与另一个单元格相邻。
您可以通过许多有趣的方式转换模式。 在draw(_:)
内部,用以下内容替换pattern
:
// 1
let transform = CGAffineTransform(translationX: 5, y: 5)
// 2
let pattern = CGPattern(
info: nil,
bounds: CGRect(x: 0, y: 0, width: 20, height: 20),
matrix: transform,
xStep: 20,
yStep: 20,
tiling: .constantSpacing,
isColored: true,
callbacks: &callbacks)
您已通过传递转换矩阵来修改CGPattern
。 下面是详细分解:
- 1) 创建表示
translation
的仿射变换矩阵。 - 2) 通过将其传递给
matrix
参数来配置模式以使用此转换。
运行playground
,注意图案如何向右和向下移动以匹配您定义的平移:
除了translating
图案外,您还可以缩放和旋转图案单元格。 您将在以后为应用程序构建模式时看到如何旋转模式。
这是你如何填充和描绘彩色图案。 在drawPattern
中替换:
context.setFillColor(UIColor.black.cgColor)
context.fillPath()
用下面的代码
context.setFillColor(UIColor.yellow.cgColor)
context.setStrokeColor(UIColor.darkGray.cgColor)
context.drawPath(using: .fillStroke)
在这里,您将填充颜色更改为黄色并设置描边颜色。 然后使用填充和描边路径的选项调用drawPath(using :)
。
运行你的playground
,检查模式现在显示你的新填充颜色和边缘:
到目前为止,您已经使用了彩色图案并在图案绘制方法中定义了颜色。 在完成的应用程序中,您必须创建具有不同颜色的图案。 您可能意识到为每种颜色编写draw
方法不是可行的方法。 这就是masking patterns
发挥作用的地方。
后记
本篇主要讲述了一个简单小游戏,感兴趣的给个赞或者关注~~~