【问题标题】:How to execute a function in a UIViewController through a SwiftUI Button?如何通过 SwiftUI 按钮在 UIViewController 中执行功能?
【发布时间】:2019-12-02 16:32:24
【问题描述】:

在下面的代码中,我试图弄清楚如何使用SwiftUI 按钮执行savePhoto 函数。这实际上是我试图解决的问题的简化版本,但仍然无法弄清楚。我在ContentView 中创建的按钮是我想象的解决问题的方法,但由于 SwiftUI 结构,我似乎找不到解决方法。

这是我的 SwiftUI 视图:

struct ContentView: View {
    var body: some View {
        ZStack{
            AnotherControllerView()
            Button(action: { AnotherControllerView.savePhoto() }){
                Text("Save Photo")
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

还有我的集成 UIViewController:

import Foundation
import SwiftUI
import UIKit

struct AnotherControllerView : UIViewControllerRepresentable {

    typealias UIViewControllerType = AnotherController

    func makeCoordinator() -> AnotherControllerView.Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<AnotherControllerView>) -> AnotherController {

        return AnotherController()
    }

    func updateUIViewController(_ uiViewController: AnotherController, context: UIViewControllerRepresentableContext<AnotherControllerView>) {

    }


    class Coordinator : NSObject {
        var parent : AnotherControllerView
        init(_ viewController : AnotherControllerView){
            self.parent = viewController
        }
    }
}

class AnotherController : UIViewController {


    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.blue
    }

    func savePhoto(){

        let alert = UIAlertController(title: "Save Photo to Camera Roll", message: "Would you like to save your drawing to the camera roll?", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
        alert.addAction(UIAlertAction(title: "Save", style: .default, handler: someHandler))
        self.present(alert, animated: true)
    }

    func someHandler(alert: UIAlertAction!) {
        print("Handler executed")
    }
}

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

    你好要控制 UIViewController 我们需要在 View 和 UIViewControllerRepresentable 之间创建一个绑定 让我们用代码解释一下: 首先,您需要在AnotherControllerView 中声明一个带有@Binding 注释的新变量

    会是这样的:

    struct AnotherControllerView : UIViewControllerRepresentable {
    
        @Binding var isShown: Bool
        typealias UIViewControllerType = AnotherController
    
        func makeCoordinator() -> AnotherControllerView.Coordinator {
            Coordinator()
        }
    
        func makeUIViewController(context: UIViewControllerRepresentableContext<AnotherControllerView>) -> AnotherController {
    
            return AnotherController(isShown: $isShown)
        }
    
        func updateUIViewController(_ controller: AnotherController, context: UIViewControllerRepresentableContext<AnotherControllerView>) {
            if(self.isShown){
                controller.savePhoto()
            }
        }
    
    
        class Coordinator : NSObject {
    
        }
    }
    

    为此,我们在updateUIViewController 中实现逻辑

    class AnotherController : UIViewController {
    
         @Binding var isShown: Bool
    
        init(isShown: Binding<Bool>) {
            _isShown = isShown
            super.init(nibName: nil, bundle: nil)
    
        }
    
    
    
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = UIColor.blue
        }
    
        func savePhoto(){
    
            let alert = UIAlertController(title: "Save Photo to Camera Roll", message: "Would you like to save your drawing to the camera roll?", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: cancelAlert))
            alert.addAction(UIAlertAction(title: "Save", style: .default, handler: someHandler))
            self.present(alert, animated: true)
        }
    
        func cancelAlert(alert: UIAlertAction!) {
            self.isShown = false
        }
    
        func someHandler(alert: UIAlertAction!) {
            print("Handler executed")
        }
    }
    

    如果你想捕捉图像,让我告诉你我是如何实现的:

    struct CaptureImageView {
        @Binding var isShown: Bool
        @Binding var image: Image?
        var sourceType: UIImagePickerController.SourceType
    
        func makeCoordinator() -> Coordinator {
            return Coordinator(isShown: $isShown, image: $image)
        }
    }
    
    extension CaptureImageView: UIViewControllerRepresentable {
        func makeUIViewController(context: UIViewControllerRepresentableContext<CaptureImageView>) -> UIImagePickerController {
            let picker = UIImagePickerController()
            picker.delegate = context.coordinator
            picker.sourceType = sourceType
            return picker
        }
    
        func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<CaptureImageView>) {
    
        }
    
        class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
            @Binding var isCoordindatorShown: Bool
            @Binding var imageInCoordinator: Image?
    
            init(isShown: Binding<Bool>, image: Binding<Image?>) {
                _isCoordindatorShown = isShown
                _imageInCoordinator = image
            }
    
            func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
                guard let unwrapImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else {return}
                imageInCoordinator = Image(uiImage: unwrapImage)
                isCoordindatorShown = false
            }
    
            func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
                isCoordindatorShown = false
            }
        }
    
    }
    

    我只是在正文中调用:

    CaptureImageView(isShown: $showCaptureImageView, image: $imageCaptured, sourceType: importSourceType)
    

    【讨论】:

    • UIViewController 的指定初始化器是 initWithNibName:bundle:。您应该改为调用它。如果您没有 nib,请为 nibName 传入 nil(bundle 也是可选的)。然后你可以在 loadView 中构建自定义视图,或者在 viewDidLoad 中为 self.view 添加子视图,就像你以前一样。
    • 非常感谢。我做了 twerk 并且能够实现我所追求的,这只是在 UIViewController 中保存一个 UIImage。但是,在执行savePhoto() 时,您没有收到双重警报吗?似乎它希望您通过 SwiftUI 运行警报。 2019-12-02 12:54:27.434741-0500 CoordinatorVC[1048:209323] Warning: Attempt to present &lt;UIAlertController: 0x101888400&gt; on &lt;CoordinatorVC.AnotherController: 0x100c13010&gt; which is already presenting (null)
    • 是的,你是对的,我得到了两次,我添加了一个警报,正如你直接在视图上所说的
    • 那么你检查是否设置了一个布尔值,当它设置时,调用相应的函数?当通过不同的状态更新再次调用updateUIViewController 时会发生什么?除非您在函数末尾重置布尔值,否则将错误地再次调用该函数。 然而如果你在函数结束时重置布尔值,那么你就会陷入状态修改循环:“在视图更新期间修改状态,这将导致未定义的行为。”
    【解决方案2】:

    如果 AnotherControllerView 很大并且您很少在新版本中使用它,您可以考虑使用更简单的解决方法。

            struct ContentAnotherControllerView: View {
    
                let   anotherControllerView = AnotherControllerView()
    
                var body: some View {
                    ZStack{
                        anotherControllerView
                        Button(action: { self.anotherControllerView.savePhoto() }){
                            Text("Save Photo")
                        }
                    }
                }
            }
    
    
    
         struct AnotherControllerView : UIViewControllerRepresentable {
    
         typealias UIViewControllerType = AnotherController
    
         var savePhotoDelegate: AnotherController? = AnotherController()
    
        func savePhoto(){
             savePhotoDelegate?.savePhoto()
         }
    
    
         func makeUIViewController(context:   UIViewControllerRepresentableContext<AnotherControllerView>) -> AnotherController {
    
        if let savePhotoDelegate = savePhotoDelegate{
            return savePhotoDelegate
        }
        return AnotherController()
        }
       ....}
    

    这种方法只是提醒我们一个视图可以在某些情况下重用。由于 UIView 桥不是纯 SwiftUI 域,你可以试试这种方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-07
      • 2020-12-18
      • 1970-01-01
      相关资源
      最近更新 更多