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

SwiftUI中Sheet加载AVKit视频时无法保持.thinMaterial透明问题

问题

我用.presentationBackground(.thinMaterial)给.sheet设置透明背景,其他Sheet都正常生效,但加载AVKit视频预览的Sheet刚打开时会显示系统默认颜色,只有等视频完全加载完成后,才会切换成.thinMaterial的透明效果。

效果对比

  • 刚点击打开Sheet时:初始效果
  • 视频加载完成后:加载完成效果

现有代码

视频加载代码

func loadVideoProperties() {
        isLoading = true // 显示加载指示器
        let asset = AVAsset(url: videoURL)
        let keys = ["playable"]

        asset.loadValuesAsynchronously(forKeys: keys) {
            DispatchQueue.main.async {
                self.isLoading = false // 隐藏加载指示器
                var error: NSError?
                let status = asset.statusOfValue(forKey: "playable", error: &error)

                if status == .loaded {
                    self.isVideoReady = true // 视频准备就绪
                    self.player = AVPlayer(playerItem: AVPlayerItem(asset: asset))
                } else if let error = error {
                    print("加载视频属性出错: \(error)")
                }
            }
        }
    }

Sheet代码

.sheet(item: $videoPreviewURL) { videoURL in
      VideoPreviewView(videoURL: videoURL.url)
      .presentationDetents([.height(560)])
      .presentationBackground(.thinMaterial)
}

解决方法

问题根源是视频加载完成前,VideoPreviewView没有足够的内容支撑Sheet背景的透明效果,导致系统 fallback 到默认背景。可以通过以下几种方式解决:

1. 给VideoPreviewView添加常驻透明背景层

在VideoPreviewView的视图结构里,提前添加一个和.thinMaterial效果一致的底层视图,确保Sheet打开瞬间就有透明背景:

struct VideoPreviewView: View {
    let videoURL: URL
    @State private var isVideoReady = false
    @State private var player: AVPlayer?

    var body: some View {
        ZStack {
            // 常驻透明背景,确保Sheet背景立即生效
            Color.clear
                .background(.thinMaterial)
                .ignoresSafeArea()

            if isVideoReady, let player = player {
                AVPlayerLayerView(player: player)
                    .onAppear { player.play() }
            } else {
                // 加载指示器放在透明背景之上
                ProgressView()
                    .foregroundColor(.white)
            }
        }
        .onAppear {
            loadVideoProperties()
        }
    }

    // 你的loadVideoProperties方法...
}

2. 给Sheet根容器强制设置透明背景

把透明背景逻辑移到Sheet的根容器里,避免子视图层级覆盖背景设置:

.sheet(item: $videoPreviewURL) { videoURL in
    ZStack {
        // 底层先铺好透明背景
        Color.clear.background(.thinMaterial).ignoresSafeArea()
        VideoPreviewView(videoURL: videoURL.url)
    }
    .presentationDetents([.height(560)])
    .presentationBackground(.clear) // 让Sheet本身背景透明,显示内层的thinMaterial
}

3. 提前初始化占位AVPlayer

在触发Sheet打开前,先初始化一个空的AVPlayer(或占位AVAsset)传递给VideoPreviewView,避免视图初始时无内容导致背景失效:

// 触发Sheet的地方
@State private var videoPreviewURL: URLWrapper?

func showVideoPreview(url: URL) {
    // 提前创建占位player
    let placeholderPlayer = AVPlayer()
    videoPreviewURL = URLWrapper(url: url, placeholderPlayer: placeholderPlayer)
}

// 修改Sheet代码
.sheet(item: $videoPreviewURL) { wrapper in
    VideoPreviewView(videoURL: wrapper.url, initialPlayer: wrapper.placeholderPlayer)
    .presentationDetents([.height(560)])
    .presentationBackground(.thinMaterial)
}

核心思路都是确保Sheet打开的瞬间,视图层级中就存在带有.thinMaterial效果的元素,不让系统有机会显示默认背景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:06:08