如何在 SwiftUI 上将来电视图显示为顶部? [英] How to display incoming call view as top on SwiftUI?

查看:42
本文介绍了如何在 SwiftUI 上将来电视图显示为顶部?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图模拟如何在所有顶部显示呼叫视图.但我有一些不清楚的地方:

I have tried to simulate how displaying the call view on the top of all. But I have some unclear points:

  • 有什么方法可以让它更简单吗?
  • 视图层次结构是否会在这种情况下受到保护?

AppView.swift

AppView.swift

import SwiftUI

struct AppView: View {
    
    @ObservedObject var callVM: CallViewModel
    
    init() {
        self.callVM = CallViewModel()
    }
    
    var body: some View {
        VStack {
            IncomingCallView(rootView: appView, isActive: self.$callVM.isIncomingCallActive)
            TabView {
                TabOne()
                    .tabItem {
                        Image(systemName: "list.dash")
                        Text("Menu")
                    }

                TabTwo()
                    .tabItem {
                        Image(systemName: "square.and.pencil")
                        Text("Order")
                    }
            }
        }
        .onAppear(perform: load)
    }
    
    var appView: some View {
        Text("")
    }
    
    func load() {
        self.callVM.getCall()
    }
}

struct AppView_Previews: PreviewProvider {
    static var previews: some View {
        AppView()
    }
}

CallViewModel.swift

CallViewModel.swift

import Foundation

class CallViewModel: ObservableObject {
    
    @Published public var isIncomingCallActive = Bool()
    
    init() {
        self.isIncomingCallActive = false
    }
    
    func getCall() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            self.isIncomingCallActive = true
        }
    }
}

IncomingCallView.swift

IncomingCallView.swift

import SwiftUI

struct IncomingCallView<RootView: View>: View {
    private let rootView: RootView
    @Binding var isActive: Bool

    init(rootView: RootView, isActive: Binding<Bool>) {
        self.rootView = rootView
        self._isActive = isActive
    }

    var body: some View {
        rootView
            .background(Activator(isActive: $isActive))
    }

    struct Activator: UIViewRepresentable {
        @Binding var isActive: Bool
        @State private var myWindow: UIWindow? = nil

        func makeUIView(context: Context) -> UIView {
            let view = UIView()
            DispatchQueue.main.async {
                self.myWindow = view.window
            }
            return view
        }

        func updateUIView(_ uiView: UIView, context: Context) {
            guard let holder = myWindow?.rootViewController?.view else { return }

            if isActive && context.coordinator.controller == nil {
                context.coordinator.controller = UIHostingController(rootView: loadingView)

                let view = context.coordinator.controller!.view
                view?.backgroundColor = UIColor.black.withAlphaComponent(1)
                view?.isUserInteractionEnabled = true
                view?.translatesAutoresizingMaskIntoConstraints = false
                holder.addSubview(view!)
                holder.isUserInteractionEnabled = true

                view?.leadingAnchor.constraint(equalTo: holder.leadingAnchor).isActive = true
                view?.trailingAnchor.constraint(equalTo: holder.trailingAnchor).isActive = true
                view?.topAnchor.constraint(equalTo: holder.topAnchor).isActive = true
                view?.bottomAnchor.constraint(equalTo: holder.bottomAnchor).isActive = true
            } else if !isActive {
                context.coordinator.controller?.view.removeFromSuperview()
                context.coordinator.controller = nil
                holder.isUserInteractionEnabled = true
            }
        }

        func makeCoordinator() -> Coordinator {
            Coordinator()
        }

        class Coordinator {
            var controller: UIViewController? = nil
        }
        
        private var loadingView: some View {
            HStack(spacing: 20) {
                
                Button(action: {
                    print("acceptCall pressed")
                    // change UI for accepted call
                }) {
                    Image("acceptCall")
                        .resizable()
                        .frame(width: 50, height: 50, alignment: .center)
                        .aspectRatio(contentMode: .fit)
                }

                Button(action: {
                    // close the view
                    print("rejectCall pressed")
                    self.isActive = false
                }) {
                    Image("rejectCall")
                        .resizable()
                        .frame(width: 50, height: 50, alignment: .center)
                        .aspectRatio(contentMode: .fit)
                }
                
            }
            .frame(width: 300, height: 300)
            .background(Color.primary.opacity(0.7))
            .cornerRadius(10)
        }
    }
}

推荐答案

仅 swiftUI 中的某些内容就会像这样

Something in just swiftUI would look like this

struct AppView: View {
    
    @StateObject var callVM = CallViewModel()
    
    var body: some View {
        ZStack {
            TabView {
                Text("TabOne")
                    .tabItem {
                        Image(systemName: "list.dash")
                        Text("Menu")
                    }
                
                Text("TabTwo")
                    .tabItem {
                        Image(systemName: "square.and.pencil")
                        Text("Order")
                    }
            }
            if callVM.isIncomingCallActive {
                ZStack {
                    Color.green
                    VStack {
                        Text("Incoming call...")
                        Button(action: { callVM.isIncomingCallActive = false }) {
                            Text("Cancel")
                        }
                    }
                }.edgesIgnoringSafeArea(.all) // <= here
            }
        }
        .onAppear {
            self.callVM.getCall()
        }
    }
}

class CallViewModel: ObservableObject {
    
    @Published public var isIncomingCallActive = false
    
    func getCall() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            self.isIncomingCallActive = true
        }
    }
}

这篇关于如何在 SwiftUI 上将来电视图显示为顶部?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆