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
相关产品推荐
相关产品推荐

