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

SwiftUI如何实现子视图全屏显示?含自定义覆盖层视频播放器场景

在SwiftUI中实现带自定义覆盖层的全屏视频播放器

核心思路

要让子视图真正脱离父视图边界占据全屏,不能仅依赖SwiftUI的ignoresSafeArea,需借助UIKit的窗口层级和视图控制器管理,同时保留SwiftUI自定义覆盖层的灵活性。

解决方案步骤

1. 创建全屏容器视图(UIKit桥接实现)

通过UIViewControllerRepresentable桥接UIKit,利用窗口层级提升让视图直接覆盖整个屏幕,不受父视图约束,同时处理屏幕旋转适配。

import SwiftUI
import AVKit

class FullScreenVideoController: UIViewController {
    var player: AVPlayer?
    var overlayView: UIView?
    var onDismiss: (() -> Void)?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        
        // 添加视频播放器层
        if let player = player {
            let playerLayer = AVPlayerLayer(player: player)
            playerLayer.frame = view.bounds
            playerLayer.videoGravity = .resizeAspectFill
            view.layer.addSublayer(playerLayer)
        }
        
        // 添加SwiftUI编写的自定义覆盖层
        if let overlayView = overlayView {
            overlayView.frame = view.bounds
            overlayView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            view.addSubview(overlayView)
        }
        
        // 监听屏幕旋转,实时调整布局
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(onScreenRotation),
            name: UIDevice.orientationDidChangeNotification,
            object: nil
        )
    }
    
    @objc private func onScreenRotation() {
        // 调整视频层尺寸
        view.layer.sublayers?.forEach { layer in
            if layer is AVPlayerLayer {
                layer.frame = view.bounds
            }
        }
        // 调整覆盖层尺寸
        overlayView?.frame = view.bounds
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        NotificationCenter.default.removeObserver(self)
        onDismiss?()
    }
}

struct FullScreenVideoContainer: UIViewControllerRepresentable {
    var player: AVPlayer
    var overlay: AnyView
    var onDismiss: () -> Void
    
    func makeUIViewController(context: Context) -> FullScreenVideoController {
        let controller = FullScreenVideoController()
        controller.player = player
        // 将SwiftUI覆盖层转为UIView
        controller.overlayView = UIHostingController(rootView: overlay).view
        controller.onDismiss = onDismiss
        // 提升窗口层级,确保覆盖所有系统UI
        controller.view.window?.windowLevel = .alert + 1
        return controller
    }
    
    func updateUIViewController(_ uiViewController: FullScreenVideoController, context: Context) {}
}

2. SwiftUI主视图中集成全屏容器

通过fullScreenCover触发全屏模式,既保留SwiftUI状态管理,又确保视频和覆盖层铺满屏幕。

struct VideoPlayerView: View {
    @State private var isFullScreen = false
    let player = AVPlayer(url: URL(string: "your-video-url")!)
    
    var body: some View {
        VStack {
            // 非全屏模式的视频预览
            VideoPlayer(player: player)
                .frame(height: 200)
                .cornerRadius(12)
            
            Button("进入全屏") {
                isFullScreen = true
            }
        }
        .fullScreenCover(isPresented: $isFullScreen) {
            FullScreenVideoContainer(
                player: player,
                overlay: AnyView(customOverlay),
                onDismiss: { isFullScreen = false }
            )
            .ignoresSafeArea()
        }
    }
    
    // 自定义覆盖层(完全用SwiftUI编写)
    private var customOverlay: some View {
        VStack {
            HStack {
                Spacer()
                Button("退出全屏") {
                    isFullScreen = false
                }
                .foregroundColor(.white)
                .padding()
            }
            
            Spacer()
            
            HStack {
                Button(player.timeControlStatus == .playing ? "暂停" : "播放") {
                    player.timeControlStatus == .playing ? player.pause() : player.play()
                }
                .foregroundColor(.white)
                .padding()
                Spacer()
            }
        }
        .background(Color.black.opacity(0.5))
    }
}

3. 关键细节说明

  • 窗口层级提升:通过windowLevel = .alert + 1让全屏视图优先于普通UI显示,彻底脱离父视图约束。
  • 旋转适配:监听设备旋转通知,实时调整视频层和覆盖层的frame,保证旋转后仍铺满屏幕。
  • 覆盖层桥接:用UIHostingController将SwiftUI视图转为UIView,既保留SwiftUI的开发便捷性,又能嵌入UIKit的全屏容器中。
  • 避免固定尺寸:使用控制器的view.bounds而非UIScreen.main.bounds,自动适配当前屏幕状态(包括旋转、刘海屏等)。

内容的提问来源于stack exchange,提问作者William

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:20:21