SwiftUI实现全局全屏悬浮视图(弃用.fullScreenCover方案)
实现独立于SwiftUI模态栈的全屏视频层
核心方案:自定义UIWindow覆盖层
SwiftUI的fullScreenCover受限于视图层级的模态状态,当已有模态视图弹出时会触发冲突,而直接使用UIKit的UIWindow可以绕过这个限制,实现类似YouTube的全屏播放效果,具体步骤如下:
创建全局窗口管理类:负责全屏窗口的显示、隐藏及布局切换
import UIKit import SwiftUI class FullScreenPlayerManager { static let shared = FullScreenPlayerManager() private var fullScreenWindow: UIWindow? // 显示全屏播放器 func showFullScreenPlayer(content: some View) { let hostingVC = UIHostingController(rootView: content) fullScreenWindow = UIWindow(frame: UIScreen.main.bounds) fullScreenWindow?.windowLevel = .alert + 1 // 确保覆盖所有模态视图 fullScreenWindow?.rootViewController = hostingVC fullScreenWindow?.makeKeyAndVisible() } // 隐藏全屏播放器 func hideFullScreenPlayer() { fullScreenWindow?.isHidden = true fullScreenWindow = nil } // 切换到小窗模式(可自定义位置尺寸) func switchToMiniPlayer(frame: CGRect) { guard let window = fullScreenWindow else { return } window.frame = frame window.windowLevel = .normal // 降低层级,允许底层界面交互 } }在SwiftUI中调用管理类:视频列表点击触发全屏,播放器内触发小窗切换
struct VideoListView: View { let videos: [Video] var body: some View { List(videos) { video in Button(action: { FullScreenPlayerManager.shared.showFullScreenPlayer( content: FullScreenPlayerView(video: video) ) }) { VideoRowView(video: video) } } } } struct FullScreenPlayerView: View { let video: Video var body: some View { ZStack { Color.black.ignoresSafeArea() VideoPlayer(player: AVPlayer(url: video.url)) Button(action: { // 示例:右下角小窗布局 let miniFrame = CGRect( x: UIScreen.main.bounds.width - 160, y: UIScreen.main.bounds.height - 240, width: 160, height: 240 ) FullScreenPlayerManager.shared.switchToMiniPlayer(frame: miniFrame) }) { Image(systemName: "arrow.down.right") .foregroundColor(.white) .padding() } .position(x: 20, y: 40) } } }关键注意事项:
windowLevel设为.alert + 1,保证全屏窗口能覆盖所有SwiftUI模态视图和系统弹窗- 小窗模式下调低
windowLevel为.normal,让底层的SwiftUI界面可正常交互 - 单例模式确保全局只有一个全屏窗口实例,避免重复创建导致的冲突
- 播放器退出时务必调用
hideFullScreenPlayer()释放窗口资源
方案优势
SwiftUI的模态视图(包括fullScreenCover)都依附于当前UIWindow的层级,而自定义UIWindow是独立的顶层容器,完全不受原有模态栈的限制,既解决了"已处于展示状态"的冲突问题,也能实现后台应用保留、边浏览边播放的需求。
内容的提问来源于stack exchange,提问作者Fogmeister
相关产品推荐
相关产品推荐

