SwiftUI中如何判断系统启动页完全消失以同步动画?
解决SwiftUI中启动页消失后Logo平滑动画的问题
要解决启动页淡出时Logo动画提前开始导致的重影问题,核心是准确捕获系统启动页完全消失的时机,而非依赖不可靠的固定延迟。以下是两种可靠的实现方案:
方案一:监听窗口可见通知
系统启动页是临时的系统窗口,当App的主窗口变为可见时,启动页已被完全移除。通过监听UIWindow.didBecomeVisibleNotification可以精准捕获这个时机:
import SwiftUI struct ContentView: View { @State private var isLaunchFinished = false // 控制Logo位置的偏移量 @State private var logoPositionOffset = CGSize.zero var body: some View { ZStack { // 主界面背景 Color.systemBackground.edgesIgnoringSafeArea(.all) // 需要动画的Logo Image("AppLogo") .offset(logoPositionOffset) // 仅当偏移量变化时触发动画 .animation(.easeInOut(duration: 0.6), value: logoPositionOffset) } .onAppear { NotificationCenter.default.addObserver( forName: UIWindow.didBecomeVisibleNotification, object: nil, queue: .main ) { _ in guard !isLaunchFinished else { return } isLaunchFinished = true // 启动Logo移动动画(示例:移动到顶部导航栏位置) logoPositionOffset = CGSize(width: 0, height: -120) } } .onDisappear { // 移除通知监听,避免内存泄漏 NotificationCenter.default.removeObserver( self, name: UIWindow.didBecomeVisibleNotification, object: nil ) } } }
方案二:利用UIViewController的viewDidAppear回调
SwiftUI的onAppear会在视图加载完成后立即触发,但此时启动页可能尚未消失。而UIKit中UIViewController的viewDidAppear方法,会在界面完全显示、启动页彻底消失后调用。我们可以通过UIHostingController包装SwiftUI视图来获取这个时机:
1. 自定义HostingController
import SwiftUI class MainHostController: UIHostingController<ContentView> { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 发送自定义通知告知启动完成 NotificationCenter.default.post( name: NSNotification.Name("LaunchScreenDidDisappear"), object: nil ) } }
2. 在App入口使用自定义HostController
@main struct MyApp: App { var body: some Scene { WindowGroup { MainHostController(rootView: ContentView()) } } }
3. 在ContentView中监听通知触发动画
struct ContentView: View { @State private var isLaunchFinished = false @State private var logoPositionOffset = CGSize.zero var body: some View { ZStack { Color.systemBackground.edgesIgnoringSafeArea(.all) Image("AppLogo") .offset(logoPositionOffset) .animation(.easeInOut(duration: 0.6), value: logoPositionOffset) } .onReceive( NotificationCenter.default.publisher( for: NSNotification.Name("LaunchScreenDidDisappear") ) ) { _ in guard !isLaunchFinished else { return } isLaunchFinished = true logoPositionOffset = CGSize(width: 0, height: -120) } } }
关键注意事项
- 绝对不要用固定延迟(如
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)):不同设备启动速度差异大,会导致动画时机不准确,要么延迟要么仍有重影。 - 必须标记
isLaunchFinished状态:避免重复触发动画(比如App从后台回到前台时)。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

