寥寥几行代码实现 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-)

相关推荐
2501_916007474 小时前
iOS文件管理工具深度剖析,从系统沙盒到跨平台文件操作的多工具协同实践
android·macos·ios·小程序·uni-app·cocoa·iphone
青茶3604 小时前
iPhone苹果手机拍的照片默认是heic如何换成jpg格式
ios·智能手机·手机·iphone
请叫我飞哥@4 小时前
Apple授权登录开发流程
ios·swift
2501_915918416 小时前
Flutter 加固方案对比与实战,多工具组合的跨平台安全体系(Flutter App 加固/IPA 成品混淆/Ipa Guard CLI/自动化安全流程)
安全·flutter·ios·小程序·uni-app·自动化·iphone
Digitally8 小时前
无需 iTunes,将 iPhone 语音备忘录传输到电脑
ios
开开心心loky19 小时前
[iOS] GCD - 线程与队列
macos·ios·objective-c·cocoa
00后程序员张21 小时前
iOS 上架费用全解析 开发者账号、App 审核、工具使用与开心上架(Appuploader)免 Mac 成本优化指南
android·macos·ios·小程序·uni-app·cocoa·iphone