当前位置: 首页 > 面试题库 >

如何在SwiftUI视图中访问自己的窗口?

佟寒
2023-03-14
问题内容

目标是可以轻松访问任何级别的SwiftUI视图层次结构的托管窗口。目的可能有所不同-
关闭窗口,退出第一响应者,替换根视图或contentViewController。与UIKit / AppKit集成有时也需要通过窗口的路径,因此…

我在这里遇到和尝试过的

像这样的东西

let keyWindow = shared.connectedScenes
        .filter({$0.activationState == .foregroundActive})
        .map({$0 as? UIWindowScene})
        .compactMap({$0})
        .first?.windows
        .filter({$0.isKeyWindow}).first

或通过在每个SwiftUI视图中添加UIViewRepresentable /
NSViewRepresentable来使用view.window看起来丑陋,沉重且不可用的窗口。

因此,我该怎么做?


问题答案:

这是我的实验结果,很适合我,因此可能对您有所帮助。已通过Xcode 11.2 / iOS 13.2 / macOS 15.0测试

该想法是使用本机SwiftUI环境概念,因为一旦注入的环境值将自动用于整个视图层次结构。所以

1)定义环境密钥。注意,需要记住避免在保留窗口上循环引用

struct HostingWindowKey: EnvironmentKey {

#if canImport(UIKit)
    typealias WrappedValue = UIWindow
#elseif canImport(AppKit)
    typealias WrappedValue = NSWindow
#else
    #error("Unsupported platform")
#endif

    typealias Value = () -> WrappedValue? // needed for weak link
    static let defaultValue: Self.Value = { nil }
}

extension EnvironmentValues {
    var hostingWindow: HostingWindowKey.Value {
        get {
            return self[HostingWindowKey.self]
        }
        set {
            self[HostingWindowKey.self] = newValue
        }
    }
}

2)将托管窗口注入到根ContentView中,而不是创建窗口(在AppDelegate或SceneDelegate中仅一次)

// window created here

let contentView = ContentView()
                     .environment(\.hostingWindow, { [weak window] in
                          return window })

#if canImport(UIKit)
        window.rootViewController = UIHostingController(rootView: contentView)
#elseif canImport(AppKit)
        window.contentView = NSHostingView(rootView: contentView)
#else
    #error("Unsupported platform")
#endif

3)仅在需要的地方使用,只需声明环境变量

struct ContentView: View {
    @Environment(\.hostingWindow) var hostingWindow

    var body: some View {
        VStack {
            Button("Action") {
                // self.hostingWindow()?.close() // macOS
                // self.hostingWindow()?.makeFirstResponder(nil) // macOS
                // self.hostingWindow()?.resignFirstResponder() // iOS
                // self.hostingWindow()?.rootViewController?.present(UIKitController(), animating: true)
            }
        }
    }
}


 类似资料:
  • 我对Android开发非常陌生,这是我的第一个Android应用程序。 下面是我的MainActivity布局: 这是MainActivity的组件树

  • 问题内容: 是否可以从函数范围内访问python函数对象属性? 例如让我们 现在,如果要返回_x属性内容“ foo”,则必须是什么?如果有可能(简单) 谢谢 更新: 我也想做以下工作: 更新2: 声明不可能(如果是这种情况),以及为什么,比提供一种方法来伪造它更令人满意,例如使用不同于函数的对象 问题答案: 解 使函数的默认参数之一成为对函数本身的引用。 用法示例: 说明 原始张贴者想要一种不需要

  • 我们为应用程序设计了一些自定义控件,如CustomButton、CustomTexView等。这些控件定义应用程序的主题并具有标准大小。现在我们正计划在我们的项目中使用SwiftUI。如何在SwiftUI结构中使用这些自定义控件? 即。 }

  • 我对中的有一个问题。 下面是我的代码: 问题:在中按下时,会像它应该的那样消失,取而代之。但是,并不会消失,而是停留在视图B的顶部。 当更改为时,如何强制关闭?请注意,也可以由以外的其他视图更改,因此只将传递给并在单击时将其设置为false并不能完成此工作。

  • 如果我尝试调用GMail API,我会得到以下错误: 首先我生成一个代币 接下来我测试令牌 我得到一个错误400错误的请求作为回报。但如果我使用不同的范围,例如谷歌,我会得到200 ok。 我认为错误是“sub”:客户的电子邮件。我尝试在谷歌控制台中添加更多的GMail,有3封邮件是自动为项目创建的,只有来自Json的邮件返回我失败,如果尝试其他邮件,包括自动为项目创建的邮件和我自己的GMail(

  • 问题内容: 最后,现在有了Beta 5,我们可以以编程方式弹出到父视图。但是,在我的应用程序中,有几个地方视图都有一个“保存”按钮,该按钮可以结束几个步骤并返回到开始。在UIKit中,我使用popToRootViewController(),但是我一直无法找到在SwiftUI中执行相同操作的方法。 以下是我尝试实现的模式的简单示例。有任何想法吗? 问题答案: 设置视图调节到一个关键是让弹出到根的工