Skip to content

SwiftUI 中 iOS 26 玻璃效果的向后兼容实现

简介

iOS 26 引入了 Liquid Glass,这是 Apple 自 iOS 7 以来最重大的设计演进。这种半透明的动态材质可以反射和折射周围的内容,为导航元素和控件创造出精致的视觉效果。

虽然新的 .glassEffect() 修饰符使实现这种设计变得简单,但大多数应用仍需要支持旧版 iOS。本文将向你展示如何创建一个可复用的 View 扩展,在 iOS 26+ 上使用原生 Liquid Glass,在旧版本上降级到 .thinMaterial

挑战

当你尝试在 iOS 26 之前的版本上使用 .glassEffect() 时,你的应用将无法编译。你需要一个解决方案:

  1. 在 iOS 26+ 上使用原生 Liquid Glass
  2. 为 iOS 18-25 提供一致的降级方案
  3. 保持视图代码简洁

解决方案

这是一个优雅处理两种情况的 View 扩展:

swift
import SwiftUI

extension View {
    /// 应用具有向前兼容性的玻璃效果。
    /// - iOS 26+:使用原生 `.glassEffect()` 呈现 liquid glass 外观
    /// - iOS 18-25:降级到 `.thinMaterial` 以保持一致性
    @ViewBuilder
    func glassedEffect(in shape: some Shape, interactive: Bool = false) -> some View {
        if #available(iOS 26.0, *) {
            self.glassEffect(interactive ? .regular.interactive() : .regular, in: shape)
                .clipShape(shape)
        } else {
            background {
                shape.fill(.thinMaterial)
            }
            .clipShape(shape)
        }
    }
}

工作原理

让我们分析关键组件:

1. @ViewBuilder 属性

@ViewBuilder 属性允许函数根据 iOS 版本返回不同的视图类型。没有它,Swift 会要求两个分支返回相同的类型。

2. 可用性检查

swift
if #available(iOS 26.0, *) {

这个编译时检查确保 Liquid Glass 代码只在 iOS 26+ 上运行。编译器知道这是安全的,并允许在该分支中使用 .glassEffect() 修饰符。

3. 原生 Liquid Glass (iOS 26+)

swift
self.glassEffect(interactive ? .regular.interactive() : .regular, in: shape)
    .clipShape(shape)

在 iOS 26+ 上,我们使用原生修饰符:

  • .regular 变体用于标准玻璃外观
  • .interactive() 用于应该响应触摸并具有缩放和闪烁效果的控件
  • shape 参数控制玻璃边界

4. Material 降级 (iOS 18-25)

swift
background {
    shape.fill(.thinMaterial)
}
.clipShape(shape)

对于旧版本,.thinMaterial 提供类似的半透明效果,与系统设计良好融合。

使用示例

带玻璃效果的基础按钮

swift
Button("添加项目") {
    // 操作
}
.padding()
.glassedEffect(in: Capsule())

交互式浮动操作按钮

swift
Button(action: 添加项目) {
    HStack(spacing: 8) {
        Image(systemName: "plus")
            .font(.system(size: 20, weight: .semibold))
        Text("添加级别")
    }
    .foregroundStyle(Color.primary)
    .padding(.horizontal, 20)
    .frame(height: 58)
    .glassedEffect(in: Capsule(), interactive: true)
    .shadow(color: Color.black.opacity(0.12), radius: 12, y: 8)
}

圆角卡片

swift
VStack(alignment: .leading) {
    Text("统计数据")
        .font(.headline)
    Text("您的每周摘要")
        .font(.subheadline)
        .foregroundStyle(.secondary)
}
.padding()
.glassedEffect(in: RoundedRectangle(cornerRadius: 16))

圆形图标按钮

swift
Button(action: 显示设置) {
    Image(systemName: "gear")
        .font(.title2)
        .frame(width: 44, height: 44)
        .glassedEffect(in: Circle(), interactive: true)
}

设计注意事项

何时使用玻璃效果

根据 Apple 的设计指南,Liquid Glass 应该保留用于导航层,而不是主要内容。考虑工具栏、浮动操作按钮和控制覆盖层。

避免嵌套玻璃

玻璃无法采样其他玻璃元素。如果你有多个相邻的玻璃元素,在 iOS 26+ 上将它们包装在 GlassEffectContainer 中以确保一致的视觉行为。

扩展更多选项

你可以扩展该扩展以支持更多玻璃变体:

swift
extension View {
    @ViewBuilder
    func glassedEffect(
        in shape: some Shape,
        variant: GlassVariant = .regular,
        interactive: Bool = false
    ) -> some View {
        if #available(iOS 26.0, *) {
            let glass: Glass = switch variant {
            case .regular: .regular
            case .clear: .clear
            }
            self.glassEffect(interactive ? glass.interactive() : glass, in: shape)
                .clipShape(shape)
        } else {
            background {
                shape.fill(.thinMaterial)
            }
            .clipShape(shape)
        }
    }
}

enum GlassVariant {
    case regular
    case clear
}

总结

支持 iOS 26 的 Liquid Glass 同时保持向后兼容性不需要复杂的抽象。一个带有 @ViewBuilder#available 检查的简单 View 扩展就能给你两全其美:新设备上的原生 Liquid Glass 和旧设备上优雅的 material 降级。

这种模式保持你的视图代码简洁——只需调用 .glassedEffect(in: Capsule()) 并让扩展处理其余部分。

参考资料