Zendesk iOS:Messaging实例嵌入导航控制器后UIBarButtonItem不显示
我之前也碰到过一模一样的问题!Zendesk的Messaging视图控制器内部会自己创建并管理导航栏组件,直接给它的navigationItem设置按钮大概率会被覆盖或者根本不生效,这里给你几个经过验证的可行方案:
方案1:给导航控制器的顶层视图控制器绑定按钮
既然我们是用UINavigationController包裹Zendesk的VC,不如直接操作导航控制器的topViewController,避开Zendesk内部的导航栏干扰:
if let zendeskSupportVC = ZendeskController().createInstance() { let navigationController = UINavigationController(rootViewController: zendeskSupportVC) // 直接给导航控制器的顶层VC设置标题和按钮 navigationController.topViewController?.title = NSLocalizedString("Contact Us", comment: "Contact Us") let dismissBtn = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissSupportPage)) navigationController.topViewController?.navigationItem.rightBarButtonItem = dismissBtn self.present(navigationController, animated: true) }
不过这个方法偶尔会因为Zendesk内部的视图生命周期触发而失效,要是碰到这种情况,可以试试方案2。
方案2:利用Zendesk官方的UI配置接口
Zendesk的Messaging SDK其实提供了自定义导航栏的配置项,我们可以在构建UI的时候就把按钮配置进去,从根源上避免被覆盖:
先修改你的createInstance方法,给MessagingConfiguration添加导航栏配置:
func createInstance() -> UIViewController? { do { let requestConfiguration = RequestUiConfiguration() var messagingConfiguration = MessagingConfiguration() // 配置导航栏标题和右侧按钮 let navConfig = NavigationBarConfiguration( title: NSLocalizedString("Contact Us", comment: "Contact Us"), rightBarButtonItems: [UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: nil)] ) messagingConfiguration.navigationBarConfiguration = navConfig let answerBotEngine = try AnswerBotEngine.engine() let supportEngine = try SupportEngine.engine() let chatEngine = try ChatEngine.engine() let zendeskVC = try Messaging.instance.buildUI( engines: [answerBotEngine, supportEngine, chatEngine], configs: [messagingConfiguration, requestConfiguration] ) return zendeskVC } catch let error { print("Error launching Zendesk: \(error)") return nil } }
这里要注意:配置里的按钮没法直接绑定target和action,我们可以在呈现后延迟一点,找到按钮再绑定:
@objc func dismissSupportPage() { self.dismiss(animated: true) } // 呈现时绑定按钮事件 if let zendeskSupportVC = ZendeskController().createInstance() { let navigationController = UINavigationController(rootViewController: zendeskSupportVC) self.present(navigationController, animated: true) { // 延迟确保视图加载完成 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { if let doneBtn = navigationController.topViewController?.navigationItem.rightBarButtonItems?.first { doneBtn.target = self doneBtn.action = #selector(self.dismissSupportPage) } } } }
方案3:自定义导航控制器子类(最稳定)
如果前两个方案都不稳,那可以创建一个自定义导航控制器子类,在viewDidAppear里强制设置导航栏按钮,确保不会被Zendesk的内部逻辑打断:
class ZendeskNavigationController: UINavigationController { weak var dismissDelegate: UIViewController? override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 强制覆盖导航栏配置 self.topViewController?.title = NSLocalizedString("Contact Us", comment: "Contact Us") let dismissBtn = UIBarButtonItem(barButtonSystemItem: .done, target: dismissDelegate, action: #selector(dismissDelegate?.dismissSupportPage)) self.topViewController?.navigationItem.rightBarButtonItem = dismissBtn } }
然后用这个子类来呈现Zendesk的VC:
if let zendeskSupportVC = ZendeskController().createInstance() { let navController = ZendeskNavigationController(rootViewController: zendeskSupportVC) navController.dismissDelegate = self self.present(navController, animated: true) }
我当时踩坑后用的是方案3,稳定性拉满,完全不会被Zendesk的内部更新干扰,你可以根据自己的场景选合适的方案。
内容的提问来源于stack exchange,提问作者danchez
相关产品推荐
相关产品推荐

