PAYATHON 2026

如何让 iOS toolbar 按钮显隐时呈现 Liquid Glass 变形动画?

数据小许

仅通过 if 插入或移除 ToolbarItem,不能保证出现演示视频中的 Liquid Glass 液滴变形动画。可以先为状态变化提供动画事务;如果需要明确控制玻璃的出现、消失或相互融合,可以使用自定义玻璃控件的公开 API。

为什么点击有效,显隐却没有变形?

按钮的按压反馈、导航切换时 toolbar 的变形,以及条件变化引起的按钮显隐,是不同的动画场景。Apple 在 WWDC25 的 SwiftUI 介绍中展示了导航切换时 toolbar 项目的变形,但这并不意味着任意条件插入都会触发相同效果。

原代码也没有显式提供动画事务。即使补上,系统 toolbar 也不一定会采用预期的玻璃过渡。所引用的官方资料没有提供强制原生 ToolbarItem 选择该效果的开关。

保留原生 toolbar 时,先检查动画事务

可以在承载 .toolbar 的视图上,针对 text.isEmpty 添加动画:

TextField("输入文本", text: $text)
    .toolbar {
        if !text.isEmpty {
            ToolbarItem(placement: .topBarTrailing) {
                Button {
                    text = ""
                } label: {
                    Image(systemName: "trash")
                }
                .accessibilityLabel("清空文本")
            }
        }
    }
    .animation(.default, value: text.isEmpty)

这会为空与非空之间的切换提供动画事务,覆盖键盘输入和其他操作引起的变化。这是一个排查步骤,具体的 toolbar 过渡仍需在目标 iOS 版本上确认,不能保证触发液滴变形。

如果使用 withAnimation,应包住真正改变 text 的操作。只包住清空按钮的动作,无法覆盖其他来源的文本变化。

需要控制玻璃显隐时,使用自定义操作区

整个按钮组完全消失时,可以使用 .materialize。它会过渡玻璃材质并淡入内容,不需要匹配另一个玻璃形状;具体语义见 Apple 的 materialize 文档。

下面使用原生 Liquid Glass API 创建自定义操作区,位置由应用布局管理:

import SwiftUI

@available(iOS 26.0, *)
struct GlassActionsView: View {
    @State private var text = ""
    @Namespace private var glassNamespace

    var body: some View {
        VStack {
            TextField("输入文本", text: $text)
                .textFieldStyle(.roundedBorder)

            GlassEffectContainer {
                HStack {
                    Spacer()

                    if !text.isEmpty {
                        Button {
                            text = ""
                        } label: {
                            Image(systemName: "trash")
                                .frame(width: 44, height: 44)
                        }
                        .buttonStyle(.plain)
                        .accessibilityLabel("清空文本")
                        .glassEffect(.regular.interactive(), in: .circle)
                        .glassEffectID("trash", in: glassNamespace)
                        .glassEffectTransition(.materialize)
                    }
                }
                .frame(height: 44)
            }
            .animation(.default, value: text.isEmpty)
        }
        .padding()
    }
}

这段代码控制自定义玻璃按钮,不会改变系统 .topBarTrailing 的内部动画。GlassEffectContainer 保持存在,条件分支负责插入或移除带玻璃效果的按钮。

如果需要按钮之间像液滴一样融合

使用同一个 GlassEffectContainer,为相关玻璃视图分别设置稳定的 glassEffectID(_:in:),再使用 .matchedGeometry 过渡。它会参考容器内附近玻璃形状的几何信息,匹配还取决于形状距离和容器的 spacing。Apple 的 matchedGeometry 文档说明了这一条件。

当整组按钮消失、没有其他玻璃形状保留时,不能期待它自动融合到不存在的目标;这种情况更适合 .materialize。不要为了融合效果额外放置没有功能的按钮。

这些自定义方式的组织方法见 Apple 的 自定义视图 Liquid Glass 指南。将 .glassEffectTransition 加到 toolbar 内的按钮上,也不能据此认定它能控制系统为 toolbar 管理的共享玻璃背景。

备注:内容仅供参考。