即使在SwiftUI为黑色背景的情况下,方向改变时也会出现白色闪烁



我有一个ZStack,我将颜色设置为黑色,然后添加一个VideoPlayer。当我旋转设备时,播放器周围仍然有白色的闪光。我玩过各种各样的想法,背景色,前景色,不透明性,但都没用。我只是希望背景是黑色的,这样看起来像一个平滑的旋转。有人有什么建议或解决方案吗?这是我的代码:

import Foundation
import SwiftUI
import AVKit
struct VideoDetail: View {

var videoIDString: String
var videoThumbURL: String
@State var player = AVPlayer()
var body: some View {

ZStack {
Color.black
.edgesIgnoringSafeArea(.all)

let videoURL: String = videoIDString
VideoPlayer(player: player)
//.frame(height: 200)
.edgesIgnoringSafeArea(.all)
.onAppear {

player = AVPlayer(url: URL(string: videoURL)!)
player.play()
}
.onDisappear {

player.pause()
}
}
.navigationBarHidden(true)
.background(Color.black.edgesIgnoringSafeArea(.all))
}
}

我感觉到你的痛苦。这是一个SwiftUI错误。SwiftUI目前的工作方式是在UIKit视图中包含视图树。在大多数情况下,SwiftUI和UIKit彼此合作得很好,但有一个特别的问题似乎是同步UIKit和SwiftUI动画。

因此,当设备旋转时,它实际上是UIKit驱动动画,因此SwiftUI必须对它可能在动画曲线上的位置做出最佳猜测,但它的猜测很差。

我们现在能做的最好的事情就是提交反馈。重复的错误报告是苹果优先处理的方式,所以每个人的错误报告越多越好。不需要很长时间。将其命名为"设备旋转上的SwiftUI动画人工制品",并在描述中写上"FB10376122的副本",以引用同一主题的现有报告。

无论如何,在此期间,我们至少可以获取封闭窗口的UIKit视图,并在那里设置背景颜色。这种解决方法是有限的,因为1(它不会改变UIKit和SwiftUI动画之间上述同步的明显"跳跃性",2(只有当背景是块色时才会有帮助。

也就是说,这里有一个WindowGroup替换和视图修改器对,它将这个变通方法联系在一起,以便与SwiftUI的其他部分尽可能好地配合使用。

示例用法:

import SwiftUI
@main
struct MyApp: App {

var body: some Scene {
// Should be at the very top of your view tree within your `App` conforming type
StyledWindowGroup {
ContentView()
// view modifier can be anywhere in your view tree 
.preferredWindowColor(.black)
}
}
}

要使用,请将以下内容复制到名为StyledWindowGroup.swift的文件中,并添加到您的项目中:

import SwiftUI
/// Wraps a regular `WindowGroup` and enables use of the `preferredWindowColor(_ color: Color)` view modifier
/// from anywhere within its contained view tree. Use in place of a regular `WindowGroup`
public struct StyledWindowGroup<Content: View>: Scene {

@ViewBuilder let content: () -> Content

public init(content: @escaping () -> Content) {
self.content = content
}

public var body: some Scene {
WindowGroup {
content()
.backgroundPreferenceValue(PreferredWindowColorKey.self) { color in
WindowProxyHostView(backgroundColor: color)
}
}
}
}
// MARK: - Convenience View Modifer
extension View {

/// Sets the background color of the hosting window.
/// - Note: Requires calling view is contained within a `StyledWindowGroup` scene
public func preferredWindowColor(_ color: Color) -> some View {
preference(key: PreferredWindowColorKey.self, value: color)
}
}
// MARK: - Preference Key
fileprivate struct PreferredWindowColorKey: PreferenceKey {
static let defaultValue = Color.white
static func reduce(value: inout Color, nextValue: () -> Color) { }
}
// MARK: - Window Proxy View Pair
fileprivate struct WindowProxyHostView: UIViewRepresentable {

let backgroundColor: Color

func makeUIView(context: Context) -> WindowProxyView {
let view = WindowProxyView(frame: .zero)
view.isHidden = true
return view
}

func updateUIView(_ view: WindowProxyView, context: Context) {
view.rootViewBackgroundColor = backgroundColor
}
}
fileprivate final class WindowProxyView: UIView {

var rootViewBackgroundColor = Color.white {
didSet { updateRootViewColor(on: window) }
}

override func willMove(toWindow newWindow: UIWindow?) {
updateRootViewColor(on: newWindow)
}

private func updateRootViewColor(on window: UIWindow?) {
guard let rootViewController = window?.rootViewController else { return }
rootViewController.view.backgroundColor = UIColor(rootViewBackgroundColor)
}
}

我遇到了同样的问题,并找到了一个解决方案:您可以设置托管窗口的根视图控制器视图的背景色。您无法在SwiftUI中直接访问此项,因此为了做到这一点,您可以使用本答案中描述的方法。

只需将包含HostingWindowFinderwithHostingWindow视图扩展复制到某个位置,并在视图中使用以下代码将背景色设置为黑色:

var body: some View {
ZStack {
// ...
}
.withHostingWindow { window in
window?.rootViewController?.view.backgroundColor = UIColor.black
}
}

在此之后,旋转时的白色边角应该消失!

只需添加

ZStack{
...
}.preferredColorScheme(ColorScheme.dark)

最新更新