你如何访问UIViewControllerRepresentable的NavigationBar属性?

5

如果在SwiftUI中使用NavigationLink()进入UIViewControllerRepresentable进行转换,如何添加按钮或更改navigationbar的标题属性。

目前我的做法如下:

import SwiftUI

/// Controls the actual action performed by the button upon taps.
struct CatagoryButton: View {

    @State var isPresenting :Bool = false

    var company : Company?
    var text : String

    var body: some View {

        NavigationLink(destination: UIKitWrapper(company: self.company, storyboardPointer: self.text)
            .navigationBarTitle(self.text)
            .edgesIgnoringSafeArea(.all),
                       isActive: self.$isPresenting,

                       label: {
            Button(action: {
                self.isPresenting.toggle()

            }){

                ZStack {

                    ButtonShadowLayer(text: text)

                    GradientBackground()
                        .mask(ButtonBaseLayer())

                    CircleAndTextLayer(text: text)
                }
            }
        })
    }
}

这是我的可表示结构体。
import SwiftUI

/// Wraps UIKIT instance in a representable that swiftUI can present.
struct UIKitWrapper: UIViewControllerRepresentable {

    //Specify what type of controller is being wrapped in an associated type.
    typealias UIViewControllerType = UIViewController

    //Company property passed from parent view. Represents the company the user selected from main view.
    private var company : Company

    //Determines which viewcontroller will be presented to user. This string corresponds to the name of the storyboard file in the main bundle.
    private var storyboardPointer : String

    init(company: Company?, storyboardPointer: String) {

        guard let company = company else {fatalError()}

        self.company = company
        self.storyboardPointer = storyboardPointer
    }

    func makeUIViewController(context: Context) -> UIViewControllerType {

        //Find user defined storyboard in bundle using name.
        let storyboard = UIStoryboard(name: storyboardPointer, bundle: .main)

        //Downcast returned controller to protocol AccessControllerProtocol. This step is required because we are not sure which storyboard will be accessed. Potential storyboard controllers that can be called all conform to this protocol. 
        //FIXME: Remove fatalError and create error enum asap.
        guard let viewController = storyboard.instantiateInitialViewController() as? AccessControllerProtocol else { fatalError() }

        //Assign user selected company object to instance property on incoming viewController.
        viewController.company = company

        //Return UINavigationController with storyboard instance view controller as root controller.
        return viewController
    }

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {

    }
}

最后,这里是一个使用可表示性的类之一。
import UIKit

class OrdersViewController: UIViewController, AccessControllerProtocol {

    var company : Company!
    @IBOutlet var companyNameLabel : UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        setBackgroundColor()
        companyNameLabel.text = company.name
        self.navigationController?.navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(self.tapRightBarButton))]
    }

    func setBackgroundColor(){

        let backgroundGradient = BackgroundGradientSetter()
        let viewWithGradient = backgroundGradient.setGradientToView(with: [DarkBlueHue_DEFAULT,LightBlueHue_DEFAULT], size: view.bounds)

        view.addSubview(viewWithGradient)
        view.sendSubviewToBack(viewWithGradient)
    }

    @objc func tapRightBarButton(){

    }
}

无论我做什么,这个按钮都不会显示出来。我不确定是否需要将其放在makeCoordinator()中,还是有些东西我没有理解。如果有人知道,请让我知道!
2个回答

1
在您的情况下,navigationControllerviewDidLoad 中尚不可用,请尝试以下演示模块中的方法。
已测试并适用于 Xcode 11.2 / iOS 13.2。

demo

class MyUIController: UIViewController {

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.navigationController?.navigationBar.topItem?.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(self.onAdd(_:)))
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // might be needed to remove injected item here
    }

    @objc func onAdd(_ sender: Any?) {
        print(">> tapped add")
    }
}

struct MyInjector: UIViewControllerRepresentable {
    func makeUIViewController(context: UIViewControllerRepresentableContext<MyInjector>) -> MyUIController {
        MyUIController()
    }

    func updateUIViewController(_ uiViewController: MyUIController, context: UIViewControllerRepresentableContext<MyInjector>) {
    }
}

struct DemoNavigationBarUIButton: View {
    var body: some View {
        NavigationView {
            MyInjector()
                .navigationBarTitle("Demo")
        }
    }
}

struct DemoNavigationBarUIButton_Previews: PreviewProvider {
    static var previews: some View {
        DemoNavigationBarUIButton()
    }
}

尝试过了,但仍然没有任何反应。 - Michael Wells
@ScottLeonard,请查看已更新的答案,其中包含完整的已测试可用代码。 - Asperi
好的,问题在于我需要使用: self.navigationController?.navigationBar.topItem?.rightBarButtonItem 而不是 self.navigationController?.navigationItem.rightBarButtonItems感谢您的帮助。 - Michael Wells
我会给你这个问题的功劳。然而,你的解决方案也没有回答问题,因为它有很多不必要的步骤,并且也没有解决使用NavigationLink进行转换的情况。该解决方案之所以有效,是因为访问的属性发生了变化。因此,如果您可以更新您的答案以反映这一点,这样其他人就不会对他们的代码进行大量不必要的更改,谢谢。 - Michael Wells

0
如果在viewDidLoad中不可用,可以尝试在viewWillAppear()中调用setupNavigation()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接