现在你应该对于 SwiftUI 有了基本概念,并了解如何显示文字内容,本章我们来看如何显示图片。我们也会学习标签(Label)的用法。
除了文字之外,图片是 iOS App 开发的另外一个基本组件。SwiftUI 提供一个名为 Image
的视图,来让开发者将图片渲染在屏幕上。首前一章的内容相似,我会建立一个简单的 App,以示范如何进行图片的处理。本章可归纳为以下几个主题:
ignoresSafeArea
来显示一个全屏幕的图片? 首先,开启Xcode 并使用“App”模板( 在 iOS 分类下),来建立一个新项目。输入项目的名称,并设定为“SwiftUIImage”。关于组织名称,你可以设定为你自己公司或组织名称, 同样的,我使用“com.appcoda”,但你可以使用自己的值。要使用SwiftUI 的话,请确认在“User Interface”选项中选取 “SwiftUI”然后点击“Next”,选取要建立项目的数据夹, 如图 3.1 所示。
项目储存完成之后,Xcode 即会载入 ContentView.swift
档,并显示一个“设计/ 预览”画布,如图 3.2 所示。
超过 4,000 个可设定的标志,SF Symbols 无缝整合了 Apple 平台的 San Francisco 系统字型,每一个标志皆设定了不同的权重与比例,可以自动对齐文字标签,并支持动态型态(Dynamic type)与粗体字(Bold Text)辅助功能,你也可以输出这些文字,以向量图形编辑工具来进一步编辑,建立具有共享特点与可用性的自订标志。SF Symbols 4 加入 700 多个新符号、增强的颜色自定义、新的检查器以及对自定义符号的改进支持。
在教你如何在屏幕显示图片之前,我们先谈一下关于图片的来源。当然,你可以在 App 中提供自己的图片。从 iOS 13 开始,Apple 导入名为“SF Symbols”的大量系统图片,可以让开发者在任何 App 中使用。iOS 16 进一步修改版释出了 SF Symbol 4 ,新增了 700 个标志,并增强的颜色设置。
这些图片是作为标志用,由于它整合了内建的 San Francisco 字型,因此使用这些标志, 并不需要额外的安装,只要你的 App 是部署在运行 iOS 13(或之后的版本)的装置,你就可以直接取得这些标志。但你要注意,现在有五组不同的符号需要考虑:
当要使用这些标志时,你需要准备的是找到标志名称。由于有超过 4,000 个符号可供使用,Apple 释出一个名为 SF Symbols (https://developer.apple.com/sf-symbols/) 个标志可以让你使用,因此你可以很容易地找到你要的标志来配合你的设计。我极力推荐你在进行下一节之前,先安装这个 App。
想要在屏幕上显示系统图片的话,你可以初始化一个 Image
视图,加上 systemName
参数,如下所示:
Image(systemName: "cloud.heavyrain")
这将会建立一个图片视图,并载入指定的系统图片。如前所述,SF Symbols 与 San Francisco 字型无缝整合。你可以很容易地应用 font
修饰器来进行图片的缩放。
Image(systemName: "cloud.heavyrain")
.font(.system(size: 100))
你可以修改字型大小来观察图片的反应,如图 3.4 所示。
同样的,因为系统图片实际上是一个字型,你可以应用其他的修饰器如之前所学过的 foregroundColor
,来修改它的外观。
例如:要修改颜色为蓝色,你可以撰写程序如下:
Image(systemName: "cloud.heavyrain")
.font(.system(size: 100))
.foregroundColor(.blue)
要加入一个下拉式阴影效果(drop shadow effect ),你只需要使用 shadow
修饰器:
Image(systemName: "cloud.heavyrain")
.font(.system(size: 100))
.foregroundColor(.blue)
.shadow(color: .gray, radius: 10, x: 0, y: 10)
在前面,我们使用了Apple 内建的图片。不过,你可能会在App 中使用自己的图片。那么,要如何使用 Image
视图来载入图片呢?
Note: 你可以任意使用自己的图片,若是你没有合适的图片,也可以至 unsplash.com 下载图片 (https://unsplash.com/photos/Q0-fOL2nqZc) ,以方便继续后面的内容。图片下载完成之后,请将档名改成“paris.jpg”。
在你的项目能够使用图片之前,首先你必须先将图片汇入素材目录( Asset Catalog ), 也就是 Assets
。假设你已经准备好图片(paris.jpg ),按下 command+0 键来开启项目导航器(Project Navigator ),并选取 Assets。现在开启 Finder,并将图片拖曳至大纲视图(Outline View ),如图 3.5 所示。
如果你是 iOS App 开发新手,这个素材目录是你储存应用程序资源如图片、颜色与数据的地方。当你将图片放入素材目录时,你可以参照它的名称来下载图片。另外,你可以设定要载入图片的装置(例如:只限 iPhone )。
要在屏幕上显示图片,可撰写程序如下:
Image("paris")
你只需要指定图片名称,可在预览画布中见到图片。然而,由于图片是高解析度图片( 4437×6656 像素),你只能见到部分图片,如图 3.6 所示。
那么,如何调整图片呢?你可以使用 resizable
修饰器,如下所示:
Image("paris")
.resizable()
默认上,图片大小调整是使用“延伸”(stretch )模式。这表示原始图片将会被放大到填满整个屏幕画面(除了顶部与底部区域之外),如图 3.7 所示。
技术上而言,这个图片填满了整个 iOS 所定义的安全区域(Safe Area )。安全区域的概念已经存在一段颇长的时间了,定义为安全布局UI 组件的视图区域。举例而言,如图 3.7 所示,这个安全区域不包含顶部列(Top Bar )(也就是状态列)与底部列(Bottom Bar ) 的区域。安全区域可以避免你不小心隐藏了系统 UI 组件,例如:状态列(Status Bar )、导航列(Navigation Bar )与标签列(Tab Bar )。
既然我们正好说到这件事, 若是你想要显示全屏幕图片, 你可以设定 ignoringSafeArea
修饰器来忽略安全区域,如图 3.8 所示。
你可以针对特定的边缘来忽略安全区域,例如:要忽略底部边缘的安全区域,你只要传送 .bottom
作为参数即可:
.ignoresSafeArea(.container, edges: .bottom)
如果你看一下前一小节这两张图片,并与原来的做比对,你应该会发现长宽比(aspect ratio )有些失真。这个延伸模式不会去管图片的长宽比,它只是将每一边延伸来填满安全区域而已。如图 3.9 所示,要保持原来的长宽比的话,你可以像这样应用 scaledToFit
修饰器:
Image("paris")
.resizable()
.scaledToFit()
另外,你可以使用 aspectRatio
修饰器,并设定内容模式(Content Mode)为. fit
,这会达成同样的结果。
Image("paris")
.resizable()
.aspectRatio(contentMode: .fit)
在某些情况下,你想要图片的长宽比保持一样,但尽可能地延伸,则你可以应用 .fill
内容模式:
Image("paris")
.resizable()
.aspectRatio(contentMode: .fill)
我们试着来限制图片的大小,这有助于你对这两种模式能更了解。frame 修饰器可以让你控制视图的大小。举例而言,设定框架(frame )的宽度为“300 点”,图片的宽度将会限制在 300 点,如图 3.10 所示。
现在将 Image
程序以下面的代码取代:
Image("paris")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 300)
这张图片会被缩小,但是仍保持原始长宽比。如果你修改内容模式为 .fill
,图片看起来与图 3.7 几乎相同,然而当你使用selectable 模式并仔细看图 3.11,长宽比是维持不变的。
你可能会注意到图片的宽度不是我们想要的,它依然占满整个屏幕宽度。要正确运作的话,你必须使用 clipped
修饰器来消除视图额外的部分,如图 3.12 所示。
除了将图片裁切为长方形之外,SwiftUI 提供其他修饰器来让你将图片裁成不同的形状,例如:圆形。举例而言,如果你想要建立圆形图片,你可以像这样使用 clipShape
修饰器:
Image("paris")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 300)
.clipShape(Circle())
这里我们指定将图片裁成圆形。你可以传送不同参数(如 Ellipse() )来建立不同形状的图片,图 3.13 为一些示例。
SwiftUI 内建了名为 opacity
的修饰器,你可以使用这个修饰器来控制图片(或者任何视图)的不透明度。你传送一个介于0 与1 的值来指定图片的不透明度。这里,“0”代表视图完全透明,“1”则代表完全不透明。
举例而言,如果你对图片视图应用了opacity
修饰器,并设定其值为“0.5”,则这个图片将会呈现半透明(partially transparent ),如图 3.14 所示。
在设计App 时,有时你需要将另一个图片或文字分层放置在图片视图之上。SwiftUI 框架提供一个名为“overlay”的修饰器给开发者,来将图片进行重叠(Overlay ),例如:你要重叠一个系统图片(如 heart.fill )至目前的图片,你可以撰写程序如下:
Image("paris")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 300)
.clipShape(Circle())
.overlay(
Image(systemName: "heart.fill")
.font(.system(size: 50))
.foregroundColor(.black)
.opacity(0.5)
)
程序中的 .overlay
修饰器带入一个 View
作为参数。在上列的程序中,我们建立其他的图片(如 heart.fill ),并将其重叠在目前图片(如 Paris )之上,如图 3.15 所示。
事实上,你可以采用任何视图来做重叠。例如:你可以重叠一个 Text
视图在图片之上。程序写法如下:
Image("paris")
.resizable()
.aspectRatio(contentMode: .fit)
.overlay(
Text("If you are lucky enough to have lived in Paris as a young man, then wherever you go for the rest of your life it stays with you, for Paris is a moveable feast.\n\n- Ernest Hemingway")
.fontWeight(.heavy)
.font(.system(.headline, design: .rounded))
.foregroundColor(.white)
.padding()
.background(Color.black)
.cornerRadius(10)
.opacity(0.8)
.padding(),
alignment: .top
)
在 overlay
修饰器,你只需要建立一个 Text
视图,而这个文字视图将会作为图片上的重叠物件。我相信你已经熟悉了 Text
视图的修饰器,我们在前面的章节已经有介绍过。我们只是修改字型与颜色,除此之外,我们加入了间距与背景颜色。另外,要特别说明的是 alignment
参数,对于 overlay
修饰器,你可以提供一个可选值(Optional Value )来调整视图的对齐。默认是置中对齐,这里我们想要将文字重叠于图片之上,如图 3.16 所示。你可以自己将值修改为“.center”或者“.bottom”,来看看结果为何。
你不止可以重叠图片或文字在另一张图片上,你也可以应用重叠来使图片变暗。将 Image
程序以下列程序替代,并看一下效果:
Image("paris")
.resizable()
.aspectRatio(contentMode: .fit)
.overlay(
Rectangle()
.foregroundColor(.black)
.opacity(0.4)
)
我们在图片上画一个矩形(Rectangle ),并将其前景色设定为“black”。为了达到变暗(darken )效果,我们设定不透明度为“0.4”,也就是 40% 的不透明度,图片现在应该变暗了。
也可以将程序重写如下完成一样的效果:
Image("paris")
.resizable()
.aspectRatio(contentMode: .fit)
.overlay(
Color.black
.opacity(0.4)
)
在 SwiftUI,正好 Color
也是一个视图,因此我们可以使用 Color.black
作为上层来将下层的图片变暗。
当你想要将一些亮色文字重叠在太亮的图片上时,这个技术尤其有用。我们将 Image
程序替换如下:
Image("paris")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300)
.overlay(
Color.black
.opacity(0.4)
.overlay(
Text("Paris")
.font(.largeTitle)
.fontWeight(.black)
.foregroundColor(.white)
.frame(width: 200)
)
)
如前所述,这个 overlay
修饰器不限于 Image
,你也可以将它应用在其他视图上。在上列的程序中,我们使用“Color.black”来使图片变暗。此外,我们也重叠并放置了一个 Text
。如果你的步骤都正确的话,你应该会见到一个“Paris”的文字放置在深色的图片上面,如图 3.17 所示。
自 iOS 15 推出后,SF Symbols 提供四种渲染模式,可以将颜色应用于符号。 根据所选择的模式,你可以为符号填上单色或多种颜色。 例如,cloud.sun.rain 是一个支持Palette Rendering 的符号。 你可以对符号应用两种或多种对比色。 下图显示如何使用 SF Symbols 应用程序测试调色板。
在 SwiftUI 中,你可以加入 symbolRenderingMode
修饰器来修改模式。 要建立具有多种颜色的相同符号,你可以编写如下代码:
Image(systemName: "cloud.sun.rain")
.symbolRenderingMode(.palette)
.foregroundStyle(.indigo, .yellow, .gray)
我们在代码中指定使用palette
模式,然后使用foregroundStyle
修饰器使用颜色。
在 iOS 16 中,SF Symbols 添加了一个名为 Variable Color 的新功能。 你可以通过修改百分比值来调整符号的颜色。 这在使用某些符号表示进度时特别有用。
你可以下载 SF Symbols 4 (https://developer.apple.com/sf-symbols/) 以试用此新功能。 安装应用程序后,选择 Variable 类别并选择其中一个符号。 在检查器中,你可以选取 Variable Color 按钮来启用该功能。 当你修改百分比值时,符号会对修改做出反应并填充其中的一部分。 以 slowmo
符号为例。 当你将百分比值设置为 60%
时,仅填充一些条形以表示进度。
可变颜色适用于 SF Symbols 内的每种渲染模式(Rendering mode)。 你可以试试修改为其他渲染模式以查看效果。
至于,要在代码中设置百分比值,你可以在建立 Image
视图时,加入 variableValue
参数并将其与百分比值一起传递:
Image(systemName: "slowmo", variableValue: 0.6)
.symbolRenderingMode(.palette)
.foregroundStyle(.indigo)
.font(.largeTitle)
在本章中,我介绍了如何以 SwiftUI 处理图片。SwiftUI 已经让开发者很容易显示图片, 并让我们使用不同的修饰器来产生各种的图片效果。如果你是独立开发者,这些新导入的 SF Symbols 会节省你寻找第三方图示的时间。
在本章所准备的示例档中,有完整的项目可以下载: