在SwiftUI中添加新窗口并将其设为关键窗口。

huangapple go评论86阅读模式
英文:

Add New Window and make it key window in SWIFTUI

问题

我想要添加一个新窗口,因为我想要创建一个全屏加载器。我已经尝试添加一个新窗口并将其设置为根视图控制器,但它没有添加到窗口层次结构中。以下是我的代码。我正在学习SwiftUI。任何帮助都将不胜感激。

let window = UIWindow()
window.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
window.backgroundColor = .blue
window.isHidden = false
window.rootViewController = UIHostingController(rootView: Text("Loading...."))
window.makeKeyAndVisible()
英文:

I want to add a new window as I want to create a a full screen loader. I have tried to add a new window in and set that as rootviewcontroller. But it is not adding into the windows hierarchy. Below is my code. I am learning swiftUI. Any help is appreciated.

let window = UIWindow()
window.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
window.backgroundColor = .blue
window.isHidden = false
window.rootViewController = UIHostingController(rootView: Text("Loading...."))
window.makeKeyAndVisible()

答案1

得分: 1

你需要包装UIActivityIndicator并使其成为UIViewRepresentable。

struct ActivityIndicator: UIViewRepresentable {

    @Binding var isAnimating: Bool
    var style: UIActivityIndicatorView.Style

    func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView {
        return UIActivityIndicatorView(style: style)
    }

    func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>) {
        isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
    }
}

然后你可以像下面这样使用它 - 这是一个加载覆盖的示例。

struct LoadingView<Content>: View where Content: View {

    @Binding var isShowing: Bool
    var content: () -> Content

    var body: some View {
        GeometryReader { geometry in
            ZStack(alignment: .center) {

                self.content()
                    .disabled(self.isShowing)
                    .blur(radius: self.isShowing ? 3 : 0)

                VStack {
                    Text("Loading...")
                    ActivityIndicator(isAnimating: .constant(true), style: .large)
                }
                .frame(width: geometry.size.width / 2,
                       height: geometry.size.height / 5)
                .background(Color.secondary.colorInvert())
                .foregroundColor(Color.primary)
                .cornerRadius(20)
                .opacity(self.isShowing ? 1 : 0)

             }
          }
       }

}
英文:

You need to wrap UIActivityIndicator and make it UIViewRepresentable.

struct ActivityIndicator: UIViewRepresentable {

@Binding var isAnimating: Bool
style: UIActivityIndicatorView.Style

func makeUIView(context: UIViewRepresentableContext&lt;ActivityIndicator&gt;) -&gt; UIActivityIndicatorView {
    return UIActivityIndicatorView(style: style)
}

func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext&lt;ActivityIndicator&gt;) {
    isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
  }
}

Then you can use it as follows – here’s an example of a loading overlay.

Note: I prefer using ZStack, rather than overlay(:_), so I know exactly what’s
going on in my implementation
struct LoadingView<Content>: View where Content: View {

@Binding var isShowing: Bool
var content: () -&gt; Content

var body: some View {
    GeometryReader { geometry in
        ZStack(alignment: .center) {

            self.content()
                .disabled(self.isShowing)
                .blur(radius: self.isShowing ? 3 : 0)

            VStack {
                Text(&quot;Loading...&quot;)
                ActivityIndicator(isAnimating: .constant(true), style: .large)
            }
            .frame(width: geometry.size.width / 2,
                   height: geometry.size.height / 5)
            .background(Color.secondary.colorInvert())
            .foregroundColor(Color.primary)
            .cornerRadius(20)
            .opacity(self.isShowing ? 1 : 0)

         }
      }
   }

}

答案2

得分: 1

如果您想显示替代窗口,您需要将新的UIWindow连接到现有的窗口场景,所以下面是在SceneDelegate中执行此操作的可能方法演示,基于发布的通知。

// 通知名称声明
let showFullScreenLoader = NSNotification.Name("showFullScreenLoader")
let hideFullScreenLoader = NSNotification.Name("hideFullScreenLoader")

// 演示替代窗口
struct FullScreenLoader: View {
    var body: some View {
        VStack {
            Spacer()
            Button("Close Loader") {
                NotificationCenter.default.post(name: hideFullScreenLoader, object: nil)
            }
        }
    }
}

// 演示主窗口
struct MainView: View {
    var body: some View {
        VStack {
            Button("Show Loader") {
                NotificationCenter.default.post(name: showFullScreenLoader, object: nil)
            }
            Spacer()
        }
    }
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow? // 主窗口
    var loaderWindow: UIWindow?  // 替代窗口

    private var subscribers = Set<AnyCancellable>()

    func makeAntherWindow() { // 创建替代窗口
        if let windowScene = window?.windowScene {
            let newWindow = UIWindow(windowScene: windowScene)
            let contentView = FullScreenLoader()
            newWindow.rootViewController = UIHostingController(rootView: contentView)

            self.loaderWindow = newWindow
            newWindow.makeKeyAndVisible()
        }
    }

    override init() {
        super.init()
        NotificationCenter.default.publisher(for: hideFullScreenLoader)
            .sink(receiveValue: { _ in
                self.loaderWindow = nil // 移除替代窗口
            })
            .store(in: &self.subscribers)
        NotificationCenter.default.publisher(for: showFullScreenLoader)
            .sink(receiveValue: { _ in
                self.makeAntherWindow() // 创建替代窗口
            })
            .store(in: &self.subscribers)
    }

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        let contentView = MainView()
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()

        }
    }
    // 其他方法...
}

请注意,上面的代码中的翻译是对Swift代码的翻译,其中包含了许多编程术语和标识符,不需要翻译的部分已被保留。

英文:

If you want to show alternate window, you have to connect new UIWindow to existed window scene, so here is a demo of possible approach to do this in SceneDelegate, based on posted notifications.

// notification names declarations
let showFullScreenLoader = NSNotification.Name(&quot;showFullScreenLoader&quot;)
let hideFullScreenLoader = NSNotification.Name(&quot;hideFullScreenLoader&quot;)

// demo alternate window
struct FullScreenLoader: View {
    var body: some View {
        VStack {
            Spacer()
            Button(&quot;Close Loader&quot;) {
                NotificationCenter.default.post(name: hideFullScreenLoader, object: nil)
            }
        }
    }
}

// demo main window
struct MainView: View {
    var body: some View {
        VStack {
            Button(&quot;Show Loader&quot;) {
                NotificationCenter.default.post(name: showFullScreenLoader, object: nil)
            }
            Spacer()
        }
    }
}


class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow? // &lt;&lt; main window
    var loaderWindow: UIWindow?  // &lt;&lt; alternate window

    private var subscribers = Set&lt;AnyCancellable&gt;()

    func makeAntherWindow() { // &lt;&lt; alternate window creation
        if let windowScene = window?.windowScene {
            let newWindow = UIWindow(windowScene: windowScene)
            let contentView = FullScreenLoader()
            newWindow.rootViewController = UIHostingController(rootView: contentView)

            self.loaderWindow = newWindow
            newWindow.makeKeyAndVisible()
        }
    }

    override init() {
        super.init()
        NotificationCenter.default.publisher(for: hideFullScreenLoader)
            .sink(receiveValue: { _ in
                self.loaderWindow = nil // remove alternate window
            })
            .store(in: &amp;self.subscribers)
        NotificationCenter.default.publisher(for: showFullScreenLoader)
            .sink(receiveValue: { _ in
                self.makeAntherWindow() // create alternate window
            })
            .store(in: &amp;self.subscribers)
    }

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        let contentView = MainView()
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()

        }
    }
    ...

huangapple
  • 本文由 发表于 2020年1月3日 20:12:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/59578434.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定