关闭 UINavigationController 中嵌入的 SwiftUI 视图

问题描述 投票:0回答:2

我在从链接深度链接到某个 SwiftUI 视图时遇到问题。

openTakeVC
就是所谓的深度链接。目前它要嵌入到 UINavigationController 中才能工作,如果我尝试仅呈现 UIHostingController 我会因以下错误而崩溃:

Thread 1: "Application tried to present modally a view controller <_TtGC7SwiftUI19UIHostingControllerV8uSTADIUM8TakeView_: 0x14680a000> that has a parent view controller <UINavigationController: 0x1461af000>."

如果未嵌入 UINavigationController 中,则关闭功能可以正常工作,但我只能使用 UINavigationController 深层链接该视图。

是否有解决此错误的方法或消除嵌入 UINavigationController 中的 UIHostingController 的方法?

func openTakeVC(take: TakeOBJ) {
            DispatchQueue.main.async {
                
                guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
                if let _ = appDelegate.window?.rootViewController as? BannedViewController { return }
                
                //let vc = TakeSingleViewController(nibName: "TakeSingleView", bundle: nil, take: take)
                let vc = UIHostingController(rootView: TakeView(take: take))
                let nav = UINavigationController(rootViewController: vc)
                nav.modalPresentationStyle = .fullScreen
                nav.setNavigationBarHidden(true, animated: false)
                
                appDelegate.window?.rootViewController?.present(vc, animated: true, completion: nil)
                UserDefaults.removeURLToContinue()
            }
        }

TakeView

@Environment(\.presentationMode) var presentationMode


  Button {
     UIImpactFeedbackGenerator(style: .light).impactOccurred()
     presentationMode.wrappedValue.dismiss()
                        
     } label: {
        Image(systemName: "xmark")
     }
  }
swift swiftui uinavigationcontroller uihostingcontroller
2个回答
0
投票

将托管控制器创建为单独的 vc 并从那里将其关闭怎么样?

采取单VC:

final class TakeSingleVC: UIViewController {
    
    var viewModel: TakeViewModel
    var subscriptions = Set<AnyCancellable>()
    
    init(viewModel: TakeViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let childView = UIHostingController(rootView: TakeView(viewModel: viewModel))
        addChild(childView)
        childView.view.frame = view.bounds
        view.addSubview(childView.view)
        childView.didMove(toParent: self)
        
        viewModel.dismissSheet
            .sink { isDismissed in
                if isDismissed {
                    childView.dismiss(animated: true)
                }
            }.store(in: &subscriptions)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

在 TakeView 中关闭

viewModel.dismissSheet.send(true)

获取ViewModel:

final class TakeViewModel: ObservableObject {
    
    // UIKit
    var dismissSheet = CurrentValueSubject<Bool, Never>(false)
}

然后将您的演示文稿更改为

let vc = TakeSingleVC(viewModel: viewModel)
let nav = UINavigationController(rootViewController: vc)

0
投票

如果未嵌入 UINavigationController 中,则关闭功能可以正常工作,但我只能使用 UINavigationController 深层链接该视图。

是否有解决此错误的方法或消除错误的方法 UIHostingController 嵌入到 UINavigationController 中?

如果 UIHostingController 是 UINavigationController 堆栈的一部分,则通过 @Environment(.dismiss) 提供的 SwiftUI DismissAction 将无法与 UIHostingController 一起使用,即使 SwiftUI 按钮在导航栏中可用。

这是因为 DismissAction 根据上下文工作

您可以使用此操作来: 关闭模式演示,例如工作表或弹出框。 从 NavigationStack 中弹出当前视图。 关闭使用 WindowGroup 或 Window 创建的窗口。 该操作的具体行为取决于您从何处调用它。

https://developer.apple.com/documentation/SwiftUI/DismissAction

当 UIHostingController 位于 UINavigationController 内时,关闭操作(如果 UIHostingController 是导航堆栈中唯一的项目)将尝试从导航堆栈中弹出而不是关闭。

您可以通过为 UIHostingController 创建自己的自定义子类来绕过它,但我不推荐该路径。然而,这种方法有其局限性,因此不会将其发布在此处的答案中。

更安全的方法是通过闭包传递到 SwiftUI 视图,您自己的关闭操作。

© www.soinside.com 2019 - 2024. All rights reserved.