You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SwiftUI中实现类似Telegram的Sheet切换动画效果?

SwiftUI实现Telegram风格的Sheet无缝切换动画

原始代码

struct Services: View {
  @State private var isFirstSheetOpen = false
  @State private var isSecondSheetOpen = false

  var body: some View {
     Button("Open sheet") {
       isFirstSheetOpen.toggle()
     }.sheet(isPresented: $isFirstSheetOpen) {
        Button("Open second sheet") {
          isFirstSheetOpen.toggle()
          // 原代码存在笔误:应为isSecondSheetOpen.toggle()
          isFirstSecondOpen.toggle()
        }.sheet(isPresented: $isSecondSheetOpen) {
          Text("Second sheet")
        }
     }
  }
}

问题描述

需要实现Telegram式Sheet切换效果:打开第二个Sheet时,第一个Sheet同步伴随动画关闭,过渡衔接自然。当前实现存在两个问题:

  • 嵌套Sheet时,第一个Sheet关闭后会意外重新打开,导致第二个Sheet弹出时机混乱
  • 并列添加两个Sheet时,切换无过渡动画;用DispatchQueue延迟打开第二个Sheet,会导致动画衔接不流畅、耗时过长

解决方案

通过单状态变量管理Sheet显示状态,结合SwiftUI原生动画实现无缝过渡,避免嵌套/并列Sheet的问题:

  1. 定义枚举标记Sheet类型
enum ActiveSheet: Identifiable {
    case first, second
    var id: Self { self }
}
  1. 完整实现代码
struct Services: View {
    enum ActiveSheet: Identifiable {
        case first, second
        var id: Self { self }
    }
    
    @State private var activeSheet: ActiveSheet?

    var body: some View {
        Button("Open sheet") {
            activeSheet = .first
        }
        // 使用sheet(item:)管理Sheet状态
        .sheet(item: $activeSheet) { _ in
            switch activeSheet {
            case .first:
                FirstSheetView(activeSheet: $activeSheet)
            case .second:
                Text("Second sheet")
            case nil:
                EmptyView()
            }
        }
        // 统一设置过渡动画
        .transition(.move(edge: .bottom).combined(with: .opacity))
        .animation(.easeInOut(duration: 0.3), value: activeSheet)
    }
}

// 抽离第一个Sheet为独立视图
struct FirstSheetView: View {
    @Binding var activeSheet: Services.ActiveSheet?
    
    var body: some View {
        Button("Open second sheet") {
            // 用withAnimation触发同步过渡动画
            withAnimation {
                activeSheet = .second
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(.white)
    }
}

关键说明

  • 使用sheet(item:)替代isPresented,精准管理Sheet切换状态,彻底避免嵌套Sheet的异常问题
  • 切换activeSheet时用withAnimation包裹,让第一个Sheet的关闭动画与第二个Sheet的打开动画同步触发,实现无缝衔接
  • 自定义过渡动画参数(如duration)可调整动画速度,更贴近Telegram的效果

内容的提问来源于stack exchange,提问作者Roman Mahotskyi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 16:36:18