关于 swiftui-liquid-glass
面向 SwiftUI 开发者的技能指南,介绍如何在 iOS 26 及更高版本中实现和审查 Liquid Glass。重点涵盖控件与导航表面的使用、动效、可访问性和旧版本回退。
主要功能
- 01Liquid Glass API 用法
- 02玻璃效果容器与融合
- 03形变标识和过渡
- 04玻璃按钮样式
- 05可访问性与版本回退检查
适用场景
- 01为浮动控件添加玻璃效果
- 02改造现有导航和控件背景
- 03审查动效与交互实现
- 04检查旧版系统和辅助功能回退
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill swiftui-liquid-glass安装后在 Claude Code 中输入/swiftui-liquid-glass确认已加载。
附带文件evals/evals.jsonreferences/liquid-glass.md
详细介绍
SwiftUI Liquid Glass
Liquid Glass 是 Apple 各平台引入的动态半透明材质。使用当前 SDK 构建时,标准 SwiftUI 栏和演示会自动采用它。自定义玻璃效果应仅用于功能控件和导航表面,而非一般内容背景。
完整的 API 参考和更多示例,请参阅 references/liquid-glass.md。
目录
工作流
根据请求选择相应的流程:
1. 使用 Liquid Glass 实现新功能
- 确定目标表面(悬浮控件、自定义栏、临时控件)。
- 决定形状、强调程度,以及各元素是真正的控件还是静态状态。
- 将成组的玻璃元素放入
GlassEffectContainer。 - 在布局和外观修饰符之后应用
.glassEffect()。 - 仅对可轻点或可聚焦的元素添加
.interactive()。 - 在视图层级随动画变化时,使用
glassEffectID(_:in:)添加形变过渡。将glassEffectTransition(_:)放在插入或移除的玻璃子视图上,而不是始终存在的容器上,并根据形变与过渡选择样式。 - 使用
if #available(iOS 26, *)控制可用性,并为较早版本提供回退方案。
2. 使用 Liquid Glass 改进现有功能
- 找出可替换为
.glassEffect()的自定义控件或导航背景。 - 将同级玻璃元素放入
GlassEffectContainer,以实现融合并提升性能。 - 将类似玻璃效果的自定义按钮替换为
.buttonStyle(.glass)、.buttonStyle(.glassProminent)或.buttonStyle(.glass(.clear))等可配置样式。按钮需要特定色调或变体时,使用.glass(_:);.glassProminent仅用于强调度较高的主要操作。 - 在发生动画插入或移除的地方添加形变过渡。
3. 检查现有的 Liquid Glass 用法
逐项检查每个效果的内容与控件归属、布局顺序、容器范围、交互性、过渡效果、可用性、辅助功能设置和回退方案。每次修正后,恢复相同的 UI 测试场景并重新运行检查清单。
核心 API 摘要
glassEffect(_:in:)
在视图后应用 Liquid Glass。默认值:Capsule 形状的 .regular 变体。
nonisolated func glassEffect(
_ glass: Glass = .regular,
in shape: some Shape = DefaultGlassEffectShape()
) -> some View
Glass 结构体
| 属性 / 方法 | 用途 |
|---|---|
.regular | 标准玻璃材质 |
.clear | 透明变体;可读性需要时,添加调暗或对比度处理 |
.identity | 无视觉效果(直接传递) |
.tint(_:) | 添加颜色色调以增强强调效果 |
.interactive(_:) | 响应触控和指针交互 |
可将它们串联使用:.regular.tint(.blue).interactive()
GlassEffectContainer
将多个玻璃视图包裹起来,以共享渲染、融合和形变效果。
GlassEffectContainer(spacing: 24) {
// child views with .glassEffect()
}
spacing 控制相邻玻璃形状开始融合的距离。将其设置为与内部布局间距相同或更大,使形状在动画过渡期间融合,而在静止时保持分离。
形变与过渡
| 修饰符 | 用途 |
|---|---|
glassEffectID(_:in:) | 视图层级变化期间用于形变的稳定标识 |
glassEffectUnion(id:namespace:) | 将多个视图合并为一个玻璃形状 |
glassEffectTransition(_:) | 控制玻璃的出现或消失方式 |
过渡选择:对于容器间距范围内的相邻效果,使用 .matchedGeometry;对于远距离插入或移除,或不应进行几何匹配的情况,使用 .materialize;只有在不需要过渡动画时才使用 .identity。
按钮样式
Button("Action") { }
.buttonStyle(.glass) // standard glass button
Button("Primary") { }
.buttonStyle(.glassProminent) // prominent glass button
Button("Media") { }
.buttonStyle(.glass(.clear)) // configurable variant; verify contrast
相关的 iOS 26 API
| API | 用途 |
|---|---|
scrollEdgeEffectStyle | 配置滚动边界的视觉效果。 |
backgroundExtensionEffect | 将同一背景延伸至安全区域边缘,并添加镜像模糊效果。 |
ToolbarSpacer | 在工具栏项目之间创建视觉间隔。 |
签名和示例请参阅 references/liquid-glass.md 中的相应章节。
代码示例
带可用性检查的玻璃按钮
if #available(iOS 26, *) {
Button("Show Status") { showStatusDetails() }
.buttonStyle(.glass)
} else {
Button("Show Status") { showStatusDetails() }
.buttonStyle(.bordered)
}
容器中成组的玻璃形状
let symbols = ["pencil", "eraser.fill", "lasso"]
GlassEffectContainer(spacing: 24) {
HStack(spacing: 24) {
ForEach(symbols, id: \.self) { symbol in
Image(systemName: symbol)
.frame(width: 56, height: 56)
.glassEffect()
}
}
}
邻近视图的形变过渡
@State private var isExpanded = false
@Namespace private var ns
var body: some View {
GlassEffectContainer(spacing: 40) {
HStack(spacing: 40) {
Image(systemName: "pencil")
.frame(width: 80, height: 80)
.glassEffect()
.glassEffectID("pencil", in: ns)
if isExpanded {
Image(systemName: "eraser.fill")
.frame(width: 80, height: 80)
.glassEffect()
.glassEffectID("eraser", in: ns)
.glassEffectTransition(.matchedGeometry)
}
}
}
Button("Toggle") {
withAnimation { isExpanded.toggle() }
}
.buttonStyle(.glass)
}
将多个视图合并为单个玻璃形状
@Namespace private var ns
GlassEffectContainer(spacing: 20) {
HStack(spacing: 20) {
ForEach(items.indices, id: \.self) { i in
Image(systemName: items[i])
.frame(width: 80, height: 80)
.glassEffect()
.glassEffectUnion(id: i < 2 ? "group1" : "group2", namespace: ns)
}
}
}
带色调的玻璃图标控件
struct GlassIconControl: View {
let icon: String
let tint: Color
let action: () -> Void
var body: some View {
Button(action: action) {
Image(systemName: icon)
.font(.title2)
.padding()
}
.buttonStyle(.glass(.regular.tint(tint)))
}
}
明亮内容上的透明玻璃操作
if #available(iOS 26, *) {
ZStack {
Capsule()
.fill(.black.opacity(0.28))
Button {
playRecap()
} label: {
Label("Play", systemImage: "play.fill")
.font(.headline)
.padding(.horizontal, 8)
}
.buttonStyle(.glass(.clear))
}
.fixedSize()
} else {
Button("Play", systemImage: "play.fill") { playRecap() }
.buttonStyle(.borderedProminent)
}
仅当背景仍能让标签和符号清晰可读时,才使用透明玻璃。 对于明亮或繁杂的背景,请添加微妙的变暗图层,或选择不那么透明的 按钮样式。
静态状态计数,而非工具栏控件
VStack(spacing: 8) {
Text("24")
.font(.headline.monospacedDigit())
.accessibilityLabel("24 options expiring")
Text("Options Expiring")
.font(.subheadline)
.foregroundStyle(.secondary)
}
// Keep read-only status out of toolbar control slots and do not add .interactive().
常见错误
| 错误 | 修正方法 |
|---|---|
| 玻璃效果装饰静态内容 | 将其用于控件/导航层。 |
只读状态使用 .interactive() 或操作槽位 | 将状态作为内容呈现,或让整个徽标成为一个真正可访问的操作。 |
| 相关效果使用嵌套容器 | 每个相关的混合/形变组使用一个 GlassEffectContainer。 |
.glassEffect() 位于内边距/框架/样式之前 | 先应用布局和外观,再添加玻璃效果。 |
| 自定义效果假设使用默认辅助功能设置 | 测试“降低透明度”“降低动态效果”、对比度和易读性。 |
| 没有 iOS 26 之前的处理路径 | 对效果进行可用性检查,并保留可用的回退方案。 |
审查清单
- 可用性:包含
if #available(iOS 26, *),并提供回退 UI。 - 容器:多个玻璃视图由
GlassEffectContainer包裹。 - 修饰符顺序:在布局/外观修饰符之后应用
.glassEffect()。 - 交互性:仅在存在用户交互时使用
.interactive()。 - 状态与操作:静态计数/状态不是工具栏控件,也不呈现按下/悬停提示。
- 过渡:形变动画使用
@Namespace和glassEffectID。 - 过渡类型:邻近效果使用
.matchedGeometry;远距离效果使用.materialize,并应用于条件式玻璃子视图。 - 一致性:相关元素的形状、色调和间距保持统一。
- 性能:限制玻璃效果的数量;对效果分组时使用容器。
- 辅助功能:启用“降低透明度”和“降低动态效果”后进行测试。
- 按钮样式:按钮使用标准的
.glass、.glassProminent或可配置的.glass(_:);需要色调或透明变体时,优先使用.glass(_:)。 - 透明玻璃对比度:明亮内容上的透明玻璃需添加变暗/对比度处理,或改用更易读的样式。
- 并发:传递给
glassEffectID/glassEffectUnion的 ID 符合Sendable;带MainActor注解的 Liquid Glass API 应留在 SwiftUI UI 代码中。
参考资料
- 完整 API 指南:references/liquid-glass.md
- Apple 文档:将 Liquid Glass 应用于自定义视图
- Apple 文档:采用 Liquid Glass