Swift中Toast视图从导航栏下方滑入的动画实现问题
解决方案
问题出在默认的.move(edge: .top)动画是从屏幕**最顶部(导航栏上方的屏幕外区域)**滑入,所以会穿过导航栏。要实现从导航栏后方滑入的效果,需要调整动画的起始位置,让Toast从导航栏所在的位置开始向下滑到目标区域。
步骤1:获取导航栏高度
首先需要获取导航栏的总高度(包含顶部安全区域),可以用GeometryReader在SwiftUI中实现:
@State private var showToast = false @State private var navigationBarHeight: CGFloat = 0
步骤2:调整Toast的位置与动画
通过offset固定Toast的最终位置在导航栏下方,同时自定义transition让动画从导航栏位置开始:
NavigationView { GeometryReader { geo in // 你的主内容视图 Button("显示Toast") { withAnimation(.easeInOut(duration: 0.3)) { showToast = true } // 2秒后自动隐藏 DispatchQueue.main.asyncAfter(deadline: .now() + 2) { withAnimation(.easeInOut(duration: 0.3)) { showToast = false } } } .onAppear { // 获取顶部安全区域高度(包含导航栏) navigationBarHeight = geo.safeAreaInsets.top } .navigationTitle("测试页面") } .overlay( Group { if showToast { ToastView() // 固定Toast在导航栏下方 .offset(y: navigationBarHeight) // 自定义动画:从导航栏位置(向上偏移导航栏高度)滑入 .transition(.offset(y: -navigationBarHeight)) } }, alignment: .top ) }
原理说明
.offset(y: navigationBarHeight):让Toast的最终位置固定在导航栏下方,和你无动画时的正常位置一致。.transition(.offset(y: -navigationBarHeight)):设置Toast出现时的起始位置为导航栏所在的区域(相对于最终位置向上偏移导航栏高度),因为导航栏的层级高于Toast,动画时Toast会被导航栏挡住上半部分,视觉上就像是从导航栏后方滑入。
备选方案(用UIKit获取精确高度)
如果safeAreaInsets.top不符合你的需求(比如自定义导航栏高度),可以通过UIKit直接获取导航栏高度:
.onAppear { guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let navController = windowScene.windows.first?.rootViewController as? UINavigationController else { return } // 导航栏自身高度 + 顶部安全区域高度 navigationBarHeight = navController.navigationBar.frame.height + (windowScene.windows.first?.safeAreaInsets.top ?? 0) }
内容的提问来源于stack exchange,提问作者nonstopcoding
相关产品推荐
相关产品推荐

