SwiftUI中如何实现导航标题显示模式的平滑切换动画?
SwiftUI中实现导航栏显示模式的平滑切换动画
直接通过withAnimation切换navigationBarTitle的displayMode时动画生硬,核心原因是SwiftUI原生对该状态的过渡动画支持不够完善,以下是两种可行的解决方案:
方案一:结合UIKit动画实现原生流畅过渡
利用UIKit成熟的导航栏动画系统,能完美复现系统自带的largeTitle与inline模式切换动画:
- 先实现一个获取当前导航控制器的辅助方法:
private func getCurrentNavigationController() -> UINavigationController? { guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = scene.windows.first, let rootViewController = window.rootViewController else { return nil } return rootViewController.children.first as? UINavigationController ?? rootViewController as? UINavigationController }
- 修改视图代码,用UIKit的
UIView.animate包裹状态切换:
struct ContentView: View { @State private var isLargeTitle = true var body: some View { NavigationView { VStack { Text("Hello, SwiftUI!") .navigationBarTitle("Title") .navigationBarTitleDisplayMode(isLargeTitle ? .large : .inline) Button("Toggle Display Mode") { UIView.animate(withDuration: 0.3, options: .curveEaseInOut) { isLargeTitle.toggle() getCurrentNavigationController()?.navigationBar.sizeToFit() } } } } } }
这种方法保留了系统largeTitle的所有特性(比如滚动时自动收缩),动画效果和原生切换完全一致。
方案二:纯SwiftUI自定义标题动画
如果不想依赖UIKit,可以自定义标题视图,完全控制动画过程:
struct ContentView: View { @State private var isLargeTitle = true var body: some View { NavigationView { VStack { Text("Hello, SwiftUI!") Button("Toggle Display Mode") { withAnimation(.easeInOut(duration: 0.3)) { isLargeTitle.toggle() } } } .toolbar { ToolbarItem(placement: .principal) { Text("Title") .font(isLargeTitle ? .largeTitle.weight(.bold) : .headline) .transition(.scale.combined(with: .opacity)) } } .navigationBarTitleDisplayMode(.inline) } } }
这种方法的优点是纯SwiftUI实现,动画流畅度高,但会失去系统largeTitle的滚动自动收缩特性,适合不需要该特性的场景。
内容的提问来源于stack exchange,提问作者Sipan Hazim
相关产品推荐
相关产品推荐

