Build interfaces with style
Swift & UI 进阶 26m

用样式构建界面

Build interfaces with style

2021年6月10日

在 Apple 官方观看视频

一句话判断

SwiftUI 在 iOS 15 中补上了样式系统这块拼图——ButtonRolecontrolSizelistStyle 等新 API 让你不用写自定义修饰符就能获得平台一致的视觉效果。

这场 Session 讲了什么

Session 聚焦 SwiftUI 的样式和外观定制能力。iOS 15 引入了一套语义化的样式 API,让你用更少的代码实现更一致的界面。核心思路是:描述你想要什么效果(“这是一个破坏性按钮”),而不是描述怎么做(“把这个按钮变成红色”)。

具体新增包括 ButtonRole(区分 destructive 和 cancel 等语义角色)、controlSize.mini.small.regular 三档控制组件大小)、prompt 参数(给 TextField 加提示文本)、以及改进的 listStyle 在不同平台上的自动适配。这些 API 的共同特点是:你只指定语义,平台负责具体渲染。

Session 还展示了 SwiftUI 在 macOS 和 watchOS 上的样式适配能力。同一个 List 视图在不同平台上自动呈现不同的外观,而不需要你写条件编译。

值得深挖的点

语义化样式 vs 硬编码样式

ButtonRole.destructive 不是简单地把按钮文字变红。它会根据上下文智能调整:在普通上下文中是红色文字,在确认弹窗的上下文中可能表现为红色填充按钮,在 watchOS 上可能是不同的图标。这个设计哲学贯穿了整个 iOS 15 的 SwiftUI 更新——你告诉系统意图,系统决定呈现。这和 UIKit 的 UIAlertAction.Style.destructive 一脉相承,但应用范围更广。

controlSize 的级联效果

controlSize 不是只影响单个组件。设置在容器上时,它会级联到所有子组件。一个 .controlSize(.small) 放在 Form 上,里面的 TextField、Picker、Button 全部变小。这解决了之前每个组件都要单独设置大小的痛点。但要注意,某些组件在 .mini 尺寸下可能省略标题文字,你需要测试实际效果。

代码片段

使用 ButtonRole 创建语义化按钮

// 破坏性操作按钮,系统自动选择合适的红色样式
Button("删除全部", role: .destructive) {
    deleteAll()
}

// 取消按钮,系统自动选择非强调样式
Button("取消", role: .cancel) {
    dismiss()
}

// 在 confirmationDialog 中组合使用
.confirmationDialog("确认删除?", isPresented: $showConfirm) {
    Button("删除", role: .destructive) { deleteItem() }
    Button("取消", role: .cancel) { }
}

controlSize 控制组件大小

// 在容器级别设置,级联到所有子组件
VStack {
    TextField("搜索", text: $searchText)
    Button("搜索") { performSearch() }
}
.controlSize(.small)

// 单独设置某个组件
Button("查看详情") { showDetail() }
    .controlSize(.large)

给 TextField 添加 prompt

// prompt 在输入框为空时显示灰色的辅助文字
TextField("邮箱地址", text: $email, prompt: Text("请输入有效邮箱"))
    .textInputAutocapitalization(.never)
    .keyboardType(.emailAddress)

// SecureField 也支持 prompt
SecureField("密码", text: $password, prompt: Text("至少 8 位字符"))

最佳实践

新项目: 用语义化 API 代替硬编码样式。按钮用 role 而不是 .foregroundColor(.red)。控件大小用 controlSize 而不是 .frame(height:)。这样你的 App 会自动跟随未来的系统设计规范。

已有项目: 检查现有代码中的 .foregroundColor(.red).accentColor(.red) 用在按钮上的地方,替换为 ButtonRole.destructive。把手动设置高度的控件改为 controlSize。这些改动不需要大规模重构,可以逐个替换。

还有什么值得关注

  • SwiftUI 的 keyboardShortcut 在 macOS 上支持更多系统快捷键。
  • iOS 15 的 submitLabel 参数控制键盘上的 return 键文字(如”搜索”、“完成”)。
  • textFieldStyle 新增 .roundedBorder,可以直接获得带圆角边框的输入框样式。
WWDC 2021