You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 09:37:40