寥寥几行代码实现 SwiftUI 超丝滑弹窗转场动画

概述

各位微秃小码农们是否已经厌倦了 SwiftUI 中千篇一律、愣头愣脑的 sheet 弹窗动画?我们能否换一个范儿来弹出窗口呢?

答案是肯定!不仅可以,而且还很容易呢!

在本篇博文中,您将学到如下内容:

概述

  1. 旧式转场的"尴尬"
  2. SwiftUI 新转场范式 总结

小伙伴们无需彷徨等待,让我们马上开始 SwiftUI 弹框转场动画的冒险之旅吧! Let's go!!!;)


1. 旧式转场的"尴尬"

在 SwiftUI 构建的 App 里,我们对于应用界面的总体架构来说有几种不同的组织方式。其中,弹出"模式视图"给人一种简单爽快的感觉,这是通过 sheet 修改器来实现的。

下面是通过 Cursor 提示词生成的 SheetContent 视图,用的是 chatGPT5 引擎:

swift 复制代码
// Sheet 内容视图
struct SheetContent: View {
    @Environment(\.dismiss) private var dismiss    
    var body: some View {
        NavigationView {
            VStack(spacing: 30) {
                // 顶部图标 - 与源按钮匹配
                Image(systemName: "plus.circle.fill")
                    .font(.system(size: 100))
                    .foregroundColor(.blue)
                    .padding(.top, 50)
                
                Text("Zoom Transition 成功!")
                    .font(.title)
                    .fontWeight(.bold)
                
                Text("这个界面通过 Zoom 动画从底部按钮展开")
                    .font(.body)
                    .foregroundColor(.secondary)
                    .multilineTextAlignment(.center)
                    .padding(.horizontal)
                
                // 示例内容
                VStack(spacing: 16) {
                    HStack {
                        Image(systemName: "checkmark.circle.fill")
                            .foregroundColor(.green)
                        Text("动画效果流畅")
                        Spacer()
                    }
                    .padding()
                    .background(Color.green.opacity(0.1))
                    .cornerRadius(10)
                    
                    HStack {
                        Image(systemName: "arrow.up.circle.fill")
                            .foregroundColor(.blue)
                        Text("从源元素展开")
                        Spacer()
                    }
                    .padding()
                    .background(Color.blue.opacity(0.1))
                    .cornerRadius(10)
                }
                .padding(.horizontal)
                
                Spacer()
                
                // 关闭按钮
                Button("关闭") {
                    dismiss()
                }
                .font(.title2)
                .foregroundColor(.white)
                .padding()
                .background(Color.blue)
                .cornerRadius(10)
                .padding(.bottom, 50)
            }
            .navigationTitle("详情")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("完成") {
                        dismiss()
                    }
                }
            }
        }
    }
}

生成的界面如下所示:

看起来 AI 生成的代码还不错吧?

接下来,再由 chatGPT 5 大脑来搞定我们的主视图:

swift 复制代码
// 主内容视图
struct MainView: View {
    var body: some View {
        NavigationView {
            VStack(spacing: 20) {
                Text("Zoom Transition 演示")
                    .font(.largeTitle)
                    .fontWeight(.bold)
                
                Text("点击底部的加号按钮")
                    .font(.title2)
                    .foregroundColor(.secondary)
                
                Spacer()
                
                // 一些示例内容
                VStack(spacing: 16) {
                    HStack {
                        Image(systemName: "star.fill")
                            .foregroundColor(.yellow)
                        Text("这是一个示例界面")
                        Spacer()
                    }
                    .padding()
                    .background(Color.gray.opacity(0.1))
                    .cornerRadius(10)
                    
                    HStack {
                        Image(systemName: "heart.fill")
                            .foregroundColor(.red)
                        Text("点击底部按钮查看 Zoom 效果")
                        Spacer()
                    }
                    .padding()
                    .background(Color.gray.opacity(0.1))
                    .cornerRadius(10)
                }
                .padding(.horizontal)
                
                Spacer()
            }
            .navigationTitle("主界面")
        }
    }
}

最后,同样让 AI 操刀生成 ZoomTransitionDemo 视图,它将会是 sheet 弹窗的绝对主宰(驱动器):

swift 复制代码
// Zoom transition 演示
struct ZoomTransitionDemo: View {    
    // 控制 sheet 的显示状态
    @State private var isPresentedNoAnim = false
    
    var body: some View {
        MainView()
            .safeAreaInset(edge: .bottom) {
                HStack {
                    Button(action: {
                        isPresentedNoAnim = true
                    }) {
                        VStack(spacing: 10) {
                            Text("旧式转场")
                            Image(systemName: "plus.circle.fill")
                                .font(.largeTitle.weight(.black))
                        }
                        .font(.title3.bold())
                        .foregroundStyle(.red.gradient)
                    }
                    
                }
            }
            .sheet(isPresented: $isPresentedNoAnim) {
                SheetContent()
            }
    }
}

现在,点击我们示例 App 主界面底部的 + 按钮,即可 sheet 蹦出急不可耐的小视图了:

不过,这种 sheet 弹出视图的转场方式貌似有点"腻歪",它太其貌不扬,我们甚至有些审美疲劳了。

还好,Apple 及时为我们提供了全新的弹窗丝滑过渡方式,无需增加繁琐的撸码,我们即可实现漂亮的转场效果。

2. SwiftUI 新转场范式

从 iOS 18(SwiftUI 6.0)开始,苹果为导航转场增加了全新的 navigationTransition 修改器方法,它的功用很简单------设置视图导航的转场样式:

除此之外,我们还需要在导航的源视图上使用 matchedTransitionSource 修改器方法才能确保"如鱼得水":

让我们利用上面两个修改器方法,将 ZoomTransitionDemo 视图的原代码进行些许修改:

swift 复制代码
struct ZoomTransitionDemo: View {
    // 用于定义共享坐标空间的命名空间
    @Namespace private var namespace
    
    // 控制 sheet 的显示状态
    @State private var isPresented = false
    
    var body: some View {
        MainView()
            .safeAreaInset(edge: .bottom) {
                HStack {
                    Button(action: {
                        isPresented = true
                    }) {
                        VStack(spacing: 10) {
                            Text("顺滑转场")
                            Image(systemName: "plus.circle.fill")
                                .font(.largeTitle.weight(.black))
                        }
                        .font(.title3.bold())
                        .foregroundStyle(.blue.gradient)
                    }
                    .matchedTransitionSource(id: "transition-id", in: namespace)
                    .padding(.trailing)
                }
            }
            .sheet(isPresented: $isPresented) {
                SheetContent()
                    .navigationTransition(.zoom(sourceID: "transition-id", in: namespace))
            }
    }
}

看到了吗?我们只是在原来主视图的弹出视图和源视图上增加了对应的视图修改器方法即可大功告成!

现在,欣赏一下全新的弹窗转场动画,小伙伴们是否爱了爱了呢?❤️

棒棒哒!💯

总结

在本篇博文中,我们讨论了如何在 iOS 18+(SwiftUI 6)中仅用寥寥几行代码就让 sheet 弹窗转场动画有了焕然一新的进化,不禁让人眼前一亮!

感谢观赏,我们再会啦!8-)

相关推荐
sweet丶4 小时前
UIWindowScene 使用指南:掌握 iOS 多窗口架构
ios
崽崽长肉肉9 小时前
swift中的知识总结(一)
ios·swift
Yakamoz10 小时前
Swift Array的写时复制
swift
2501_9151063211 小时前
HTTP 协议详解,HTTP 协议在真实运行环境中的表现差异
网络·网络协议·http·ios·小程序·uni-app·iphone
汉秋13 小时前
SwiftUI 中的 compositingGroup():真正含义与渲染原理
swiftui·swift
柯南二号13 小时前
【大前端】【iOS】iOS 真实项目可落地目录结构方案
前端·ios
2501_9160074714 小时前
iOS与Android符号还原服务统一重构实践总结
android·ios·小程序·重构·uni-app·iphone·webview
汉秋14 小时前
SwiftUI 中的 @ViewBuilder 全面解析
swiftui·swift
二流小码农15 小时前
鸿蒙开发:自定义一个圆形动画菜单
android·ios·harmonyos
00后程序员张16 小时前
fastlane 结合 appuploader 命令行实现跨平台上传发布 iOS App
android·ios·小程序·https·uni-app·iphone·webview