SwiftUI原生Sheet内导航时如何实现高度自适应动画?
SwiftUI原生Sheet实现导航时高度自适应平滑动画
可以通过SwiftUI原生组件实现你要的效果,核心是在Sheet内部用NavigationStack管理导航流程,配合动态的presentationDetents设置,再通过withAnimation触发高度变化的平滑过渡,无需自定义Sheet视图。
实现代码示例
import SwiftUI // 定义Sheet内的导航步骤 enum SheetViewStep: Identifiable { case first, second, third var id: Self { self } } struct ContentView: View { @State private var currentSheetStep: SheetViewStep? var body: some View { Button("打开Sheet") { currentSheetStep = .first } .sheet(item: $currentSheetStep) { _ in NavigationStack { sheetContentView(for: currentSheetStep ?? .first) .navigationTitle(titleForStep(currentSheetStep)) .navigationBarTitleDisplayMode(.inline) } // 动态设置Sheet高度 .presentationDetents([.height(heightForStep(currentSheetStep))]) .presentationDragIndicator(.visible) } } // 根据步骤返回对应视图 @ViewBuilder private func sheetContentView(for step: SheetViewStep) -> some View { switch step { case .first: VStack(spacing: 30) { Text("第一步\n矮高度视图") .multilineTextAlignment(.center) .font(.title) Button("进入第二步") { withAnimation { currentSheetStep = .second } } } .padding() case .second: VStack(spacing: 30) { Text("第二步\n中等高度视图") .multilineTextAlignment(.center) .font(.title) Button("进入第三步") { withAnimation { currentSheetStep = .third } } Button("返回第一步") { withAnimation { currentSheetStep = .first } } } .padding() case .third: VStack(spacing: 30) { Text("第三步\n最高高度视图") .multilineTextAlignment(.center) .font(.title) Button("返回第二步") { withAnimation { currentSheetStep = .second } } } .padding() } } // 对应步骤的标题 private func titleForStep(_ step: SheetViewStep?) -> String { switch step { case .first: return "第一步" case .second: return "第二步" case .third: return "第三步" default: return "" } } // 对应步骤的Sheet高度 private func heightForStep(_ step: SheetViewStep?) -> CGFloat { switch step { case .first: return 220 case .second: return 400 case .third: return 600 default: return 220 } } }
关键实现要点
- 内部导航管理:用
NavigationStack在Sheet内部承载所有导航视图,避免了使用isPresented时的视图重载,或item绑定错误导致的Sheet关闭重开问题。 - 动态高度+动画:通过
presentationDetents根据当前步骤动态设置Sheet高度,切换步骤时用withAnimation包裹状态变更,触发高度变化的平滑过渡动画。 - 状态连续性:用
@State变量currentSheetStep管理导航流程,保证Sheet始终处于打开状态,仅内部视图和高度发生变化。
如果需要根据视图内容自动计算高度(而非固定值),可以结合GeometryReader获取内容的实际高度,再传递给presentationDetents,但固定高度的方式在布局稳定性上表现更好。
内容的提问来源于stack exchange,提问作者Froig
相关产品推荐
相关产品推荐

