Text
是收缩型视图。Text
无论被如何截断,文本视图都会位于主视图的中心。除非被告知将视图放置在其他位置,否则它将相对于屏幕中心放置// 基本调用方法:Text 后面跟的参数必须是 String 类型
Text("Stay Hungry. Stay Foolish.")
// 字符串插值:如果要展示的信息不是 String 类型,需要用 \\() 进行插值
Text("\\(price)")
// Text也可以用于展示 Image:
Text(Image(systemName: "person"))
.font(.system(.largeTitle, weight: .bold))
<aside> 💡 关于 iOS 设备默认的可用字体可以看这: http://iosfonts.com/ 。如果没有合适的字体,你还可以使用自己下载的合法的第三方字体。
</aside>
首先下载字体文件,并拖入项目文件夹里。
将字体文件拖到 Xcode 的项目导航器中。可以一次拖动包含 TrueType (.ttf) 或 OpenType (.otf) 文件的整个文件夹。接受默认设置;您确实想要复制项目、创建组并添加到当前目标。
您可以通过在项目导航器中选择字体文件,然后使用 Command-Option-1 打开 Xcode 的文件检查器窗格来检查字体文件是否已正确添加到当前目标。在项目导航器中突出显示每个字体文件,并确保其目标成员资格显示您应用程序的目标。
制作修改器 ViewModifier (其中字体名不需要加后缀)
struct CustomFontModifier : ViewModifier {
var size : CGFloat = 28
func body(content: Content) -> some View {
content
.font(.custom("Oswald-Regular", size: size))
}
}
修改 Info.plist
属性列表,新增 【Fonts provided by application】 字段
点击最左边导航中的项目根图标,找到Targets,点击项目名,在右边找到 info 子菜单。在Custom iOS Target Properties中,新增 Fonts provided by application 。做完后,左侧的项目导航目录里会多一项 info 文件。在 Fonts provided by application 里新增 item,后面填上字体的名称即可,有几个字体就新增几项。
在字段里逐个填入 item,即字体文件名,如:Oswald-Bold.ttf
// 可以用 + 号连接多个文本(默认基线会对齐)
Text("Here is another ")
+ Text("example").foregroundColor(.red).underline()
+ Text("Notice").foregroundColor(.purple).bold()
+ Text("as a whole.").bold().italic()
// 可以用 + 号连接多个文本(设置基线偏移,解决基线不对齐问题,负数代表往下)
Text("100").bold()
+ Text(" SWIFTUI ")
.baselineOffset(-12)
+ Text ("VIEWS").bold()
// 使用 + 号连接的带修饰符的 Text,修饰符只影响其所属 Text
Text("Hello Developer!") + Text("How are you?")
.font(.title)
.italic()
// 如果希望影响全部 Text,可以用括号把所有 Text 包括起来
(Text("Hello Developer!") + Text(" How are you?"))
.font(.title)
.italic()
<aside> 💡
【文本连接】和【字符串插值】两种方式都可以实现文本的连接,但它们之间对本地化翻译有一些不同的影响。总之,文本连接对于简单的样式场景非常有效,但最佳做法是始终优先使用文本插值,以确保语法正确且翻译自然。具体查看:
</aside>
// 1. 将文本显示为占位符
// SwiftUI 允许将文本标记为视图中的占位符,这意味着它会被渲染,但会被灰色遮盖以表明它不是最终内容。
// 这是通过 redacted(reason:) 修饰符以及可用于根据需要覆盖密文的 unredacted() 修饰符提供的。
Text("This is placeholder text").redacted(reason: .placeholder)
// 还可以加到父元素上
VStack(alignment: .leading) {
Text("This is placeholder text This is placeholder telder tex")
Text("And so is this")
}.redacted(reason: .placeholder)
// 2. 还可以查询从环境传入的任何编辑原因
struct ContentView: View {
@Environment(\\.redactionReasons) var redactionReasons
let bio = "The rain in Spain falls mainly on the Spaniards"
var body: some View {
if redactionReasons == .placeholder {
Text("Loading…")
} else {
Text(bio)
.redacted(reason: redactionReasons)
}
}
}
// 3. 还允许将视图的某些部分标记为包含敏感信息,这使我们可以使用密文更轻松地隐藏或显示它
// 要使用此功能请将 privacySensitive() 修饰符添加到应隐藏的任何视图
// 然后在更高的视图层次结构中应用 .redacted(reason: .privacy) 修饰符
VStack {
Text("Card number")
.font(.headline)
if redactionReasons.contains(.privacy) {
Text("[HIDDEN]").privacySensitive()
} else {
Text("1234 5678 9012 3456").privacySensitive()
}
}
.redacted(reason: .privacy)
// 4.默认情况下,隐私敏感上下文被灰色框屏蔽,但您也可以通过从环境中读取密文原因来提供自定义布局:
struct ContentView: View {
@Environment(\\.redactionReasons) var redactionReasons
var body: some View {
VStack {
Text("Card number")
.font(.headline)
if redactionReasons.contains(.privacy) {
Text("[HIDDEN]")
} else {
Text("1234 5678 9012 3456")
}
}
}
}
Text
视图提供了两种使用 Markdown 设置文本样式的方法:直接在 Text
视图中和使用 AttributedString
。
直接在 Text
视图中使用 Markdown 对于静态文本来说很方便,但对于动态字符串或当您想要将样式应用于字符串的不同部分时,您需要使用 AttributedString
以编程方式。
// SwiftUI 内置了对 Markdown 渲染的支持,包括粗体、斜体、链接等
// 它实际上内置于 SwiftUI 的 Text 视图中,因此您可以编写如下代码:
VStack {
Text("This is regular text.")
Text("* This is **bold** text, this is *italic* text, and this is ***bold, italic*** text.")
Text("~~A strikethrough example~~")
Text("`Monospaced works too`")
Text("Visit Apple: [click here](<https://apple.com>)")
// 该链接是可自动点击的。默认情况下,Markdown 链接将使用应用程序的强调色,但可以使用 tint() 修饰符更改它:
Text("Visit Apple: [click here](<https://apple.com>)")
.tint(.indigo)
// 注意:不支持图像
}
// 支持自动 Markdown 转换是因为 SwiftUI 将这些字符串解释为 LocalizedStringKey 实例(即可以由应用程序本地化的字符串)
// 这意味着如果您想从属性或变量创建 Markdown 文本,您应该将其显式标记为 LocalizedStringKey 以获得 Markdown 渲染:
struct ContentView: View {
let markdownText: LocalizedStringKey = "* This is **bold** text, this is *italic* text, and this is ***bold, italic*** text."
var body: some View {
Text(markdownText)
}
}
// 如果希望原始文本保持不变(即将原始的、未格式化的 Markdown 符号保留在原处),只需删除 LocalizedStringKey 注释即可
// 或者,您可以使用 Text(verbatim:) 初始值设定项完全禁用 Markdown 和本地化。
https://nilcoalescing.com/blog/HandlePluralsInSwiftUITextViewsWithInflection/
https://samwize.com/2025/04/11/plurals-with-swiftui/?utm_source=substack&utm_medium=email
解决英文复数的展示问题,一般有以下做法:
最偷懒的做法是写成固定文本的 cup(s)
第二种做法是使用三元运算符来纠正这个问题,如下所示:
Text(
question.questionNotes.count == 1 ?
NSLocalizedString("one_note", comment: "") :
String(format: NSLocalizedString("multiple_notes", comment: ""), question.questionNotes.count)
)
// 这种做法要注意本地化语言时,要添加两种状态的文案
// 英文 Localizable.strings (English)
one_note = "1 note";
multiple_notes = "%d notes";
Foundation 框架有一个称为自动语法协议的功能,它可以确保文本遵循复数和性别等语法规则。它与 SwiftUI 无缝协作,允许我们直接在文本视图中处理复数,而无需任何额外的手动逻辑。要使文本自动调整为复数值,我们可以指定它使用 inflection rule
,并定义其范围:
Text("You read ^[\\(bookCount) book](inflect: true) this year!")
Stepper("^[\\(coffeeAmount) cup](inflect: true)", value: $coffeeAmount, in: 1...20)
SwiftUI 将此语法识别为自定义 Markdown 属性,当使用字符串文本创建文本视图时,SwiftUI 会将字符串视为 LocalizedStringKey
并解析它包含的 Markdown。它识别字符串中的变形属性,并使用 Foundation 的自动语法一致性功能在渲染过程中应用必要的调整。
这种集成使 SwiftUI 中的复数处理变得简单而高效。自动语法一致性功能和 inflection 属性是在 iOS 15 中引入的,最初支持英语和西班牙语。多年来,语法引擎已扩展到包含其他语言,从 iOS 18 开始,它还支持德语、法语、意大利语、葡萄牙语、印地语和韩语,使其在多语言应用程序中更加通用。
<aside> 💡
当使用方案 3 时有一个问题,例如: .accessibilityHint("^[\\(filter.activeIssuesCount) issue](inflect: true)")
这时如果启用 VoiceOver 将看到错误:ERROR: ^[%lld issue] (inflect: true) not found in table Localizable of bundle
因为 [\\(filter.activeIssuesCount) issue]
的其中一部分是特殊 Markdown 语法,另一部分 %lld 是整数的 Localizable.strings 格式,这是我们的字符串插值中要替换的格式。虽然可以将此文本添加到 Localizable.strings 文件中,但这不是一个长久的解决方案,因为自动语法协议不支持其他语言,例如匈牙利语!
英语的复数形式不规则,即使涉及0个项目也使用复数形式。但也有更复杂的语言,例如,阿拉伯语有一种形式表示一个对象的零,另一种形式表示一个,另一个形式表示两个,另一个形式表示几个对象,另一种形式表示许多对象,还有一个形式表示所有其他计数。我们可以尝试用 Swift 对这些规则进行编码,但这比你想象的要困难得多。例如,俄语也有特殊的复数规则,当存在许多对象时,但俄语中“许多”的定义与阿拉伯语中的“许多”不同!
</aside>
基于以上方案的语言本地化问题,因此需要一个更好的解决方案。终极保险的方法还是用 Localizable.stringsdict
具体参照这里:4. 解决英语复数的问题 (这样不管是展示复数,还是本地化,都没有问题)
Text
视图能够渲染 Foundation 的 AttributedString
结构,从而实现添加下划线、删除线、网页链接、背景颜色等效果。对于更高级或动态的样式, AttributedString
是首选工具。它允许您将不同的样式应用于字符串的不同部分。
AttributedString
的创建方式,是先声明一个 AttributedString
对象,然后再用点语法设置各个属性。
struct ContentView: View {
// 声明:先声明一个 AttributedString 对象,再设置其各种属性
var message: AttributedString {
var result = AttributedString("Hello, world!")
result.font = .largeTitle
return result
}
// 使用时:作为字符串传入到 Text
var body:some View {
Text(message)
}
}
遗憾的是, AttributedString
的 API 不大透明 ,所以这里展示一大堆示例来帮助入门。
// 字体大小
result.font = .largeTitle
// 前景色
result.foregroundColor = .white
// 背景色
result.backgroundColor = .red
// 下划线图案和颜色
result.underlineStyle = Text.LineStyle(pattern: .solid, color: .white)
// 使用 link 属性将可点击的网络链接附加到文本中
result.link = URL(string: "<https://www.hackingwithswift.com>")
// 还可以调整字符串各部分的基线偏移,强制将其放置在高于或低于默认值的位置:
struct ContentView: View {
var message: AttributedString {
let string = "The letters go up and down"
var result = AttributedString()
for (index, letter) in string.enumerated() {
var letterString = AttributedString(String(letter))
letterString.baselineOffset = sin(Double(index)) * 5
result += letterString
}
result.font = .largeTitle
return result
}
var body:some View {
Text(message)
}
}
使用 AttributedString 让 Text 展示多个样式:
该示例仅使用 Text
和常规 SwiftUI 修饰符来完成,但 AttributedString
的部分功能是自定义属于 String
而不是 Text
。这意味着背景颜色是 String
本身的一部分,因此如果需要,我们可以使用不同的背景颜色将多个 String
合并在一起:
struct ContentView: View {
// 声明红色背景的字符串
var message1: AttributedString {
var result = AttributedString("Hello")
result.font = .largeTitle
result.foregroundColor = .white
result.backgroundColor = .red
return result
}
// 声明蓝色背景的字符串
var message2: AttributedString {
var result = AttributedString("World!")
result.font = .largeTitle
result.foregroundColor = .white
result.backgroundColor = .blue
return result
}
// 使用时:
// 如果您尝试对 Text 使用 background() 修饰符,会发现它不起作用。
var body:some View {
Text(message1 + message2)
}
}
<aside>
💡 您可以将 SwiftUI 修饰符与 AttributedString
属性混合使用。重要的是,通过 AttributedString
应用的属性优先于 SwiftUI 修饰符。
</aside>
在此示例中, AttributedString
使用 Markdown 语法来制作一些斜体文本。当此 AttributedString
传递到 Text
视图时,这些样式将被保留。当将 font
和 foregroundColor
修饰符应用于 Text
视图时,这些样式将应用于整个文本,但它们不会覆盖粗体和由 AttributedString
指定的斜体样式。
这是因为 AttributedString
的样式优先于 SwiftUI 修饰符。
let quote = """
**"Be yourself;** everyone else is _already taken._"
- **Oscar Wilde**
"""
let attributedQuote = try! AttributedString(markdown: quote)
struct ContentView: View {
var body: some View {
Text(attributedQuote)
.font(.system(size: 16, weight: .medium, design: .serif))
.foregroundColor(.blue)
}
}
AttributedString
真正强大的功能是它不会丢弃我们提供的有关字符串的所有元数据,这解锁了大量额外的功能。例如,出于可访问性原因,我们可以将字符串的一部分标记为需要拼写,以便在使用 VoiceOver 时正确读出密码等内容:
struct ContentView: View {
var message: AttributedString {
var password = AttributedString("abCayer-muQai")
password.accessibilitySpeechSpellsOutCharacters = true
return "Your password is: " + password
}
var body:some View {
Text(message)
}
}
更令人印象深刻的是它处理结构化信息的方式。