长按后修改TabBarController中leftBarButtonItem的实现方案
问题需求
触发UsersController中的长按操作后,修改TabViewController(继承自TabmanViewController)里配置的leftBarButtonItem。目前已在TabViewController中完成leftBarButtonItem的初始化配置,且UsersController内已实现长按手势处理方法handleLongPress。
现有代码片段
TabViewController代码
class TabViewController: TabmanViewController { private var viewControllers = [ DashboardController(),ClientsController(), UsersController() ] var viewModel = TabBarViewModel() var coordinator: TabBarCoordinator? override func viewDidLoad() { super.viewDidLoad() self.title = "Dashboard" let rightItem = UIImage(named: "userIcon") let leftItem = UIImage(named: "backMenuButton") let rightButton = UIBarButtonItem(image: rightItem, style: .done, target: self, action: #selector(rightAction)) let leftButton = UIBarButtonItem(image: leftItem, style: .done, target: self, action: #selector(leftAction)) self.navigationItem.rightBarButtonItem = rightButton self.navigationItem.leftBarButtonItem = leftButton } @objc private func rightAction() { /* 原有逻辑 */ } @objc private func leftAction() { /* 原有逻辑 */ } }
UsersController长按处理代码
@objc func handleLongPress(longPressGesture: UILongPressGestureRecognizer) { let longPress = longPressGesture.location(in: self.usersTableView) usersTableView.allowsMultipleSelection = true let indexPath = self.usersTableView.indexPathForRow(at: longPress) UINotificationFeedbackGenerator().notificationOccurred(.success) if indexPath == nil { print("Long press on table view, not row.") } else if (longPressGesture.state == UIGestureRecognizer.State.began) { print("Long press on row, at \(indexPath!.row)") if !previousIndexPath.isEmpty { } } if let selectedIndexPath = self.usersTableView.indexPathForSelectedRow { self.usersTableView.deselectRow(at: selectedIndexPath, animated: true) } userLabel.text = "Select" usersNumber.text = "0" plusButton.isHidden = true }
实现方案
以下提供三种iOS跨控制器通信的实现方式,按耦合度从低到高排序:
方案一:通知中心(NotificationCenter)—— 低耦合
通过系统通知中心实现跨控制器事件传递,适合无直接关联的控制器场景。
- 在TabViewController中注册通知监听
在viewDidLoad方法末尾添加通知注册代码,并实现处理方法:
override func viewDidLoad() { // 原有代码... // 注册自定义通知,监听长按触发事件 NotificationCenter.default.addObserver(self, selector: #selector(updateLeftBarButton(_:)), name: NSNotification.Name(rawValue: "UsersLongPressTriggered"), object: nil) } // 处理通知,更新leftBarButtonItem @objc private func updateLeftBarButton(_ notification: Notification) { // 通过userInfo传递自定义参数,比如新按钮的图片名 let newImageName = notification.userInfo?["newImageName"] as? String ?? "newBackButton" guard let newLeftImage = UIImage(named: newImageName) else { return } let newLeftButton = UIBarButtonItem(image: newLeftImage, style: .done, target: self, action: #selector(leftAction)) self.navigationItem.leftBarButtonItem = newLeftButton } // 销毁时移除监听,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) }
- 在UsersController的长按方法中发送通知
在handleLongPress的began状态分支中添加通知发送代码:
else if (longPressGesture.state == UIGestureRecognizer.State.began) { print("Long press on row, at \(indexPath!.row)") // 发送通知,传递新按钮图片名(按需修改) NotificationCenter.default.post( name: NSNotification.Name(rawValue: "UsersLongPressTriggered"), object: nil, userInfo: ["newImageName": "selectedBackButton"] ) if !previousIndexPath.isEmpty { } }
方案二:代理模式(Delegate)—— 类型安全
通过自定义协议实现控制器间强类型通信,适合明确层级关系的场景,可读性和可维护性更高。
- 定义代理协议
在UsersController外部定义协议:
protocol UsersControllerLongPressDelegate: AnyObject { /// 长按触发时调用,可传递参数 func usersControllerDidTriggerLongPress(_ controller: UsersController, newLeftBarButtonImageName: String) }
- 修改UsersController添加代理属性
class UsersController: UIViewController { // 代理属性,使用weak避免循环引用 weak var longPressDelegate: UsersControllerLongPressDelegate? // 原有长按方法... @objc func handleLongPress(longPressGesture: UILongPressGestureRecognizer) { // 原有代码... else if (longPressGesture.state == UIGestureRecognizer.State.began) { print("Long press on row, at \(indexPath!.row)") // 调用代理方法 longPressDelegate?.usersControllerDidTriggerLongPress(self, newLeftBarButtonImageName: "selectedBackButton") if !previousIndexPath.isEmpty { } } // 原有代码... } }
- TabViewController设置代理并实现协议
修改TabViewController中创建viewControllers的逻辑,设置代理并遵循协议:
class TabViewController: TabmanViewController, UsersControllerLongPressDelegate { // 修改viewControllers的初始化方式,方便设置代理 private var viewControllers: [UIViewController] { let dashboardVC = DashboardController() let clientsVC = ClientsController() let usersVC = UsersController() // 设置代理 usersVC.longPressDelegate = self return [dashboardVC, clientsVC, usersVC] } // 原有viewDidLoad代码... // 实现代理方法 func usersControllerDidTriggerLongPress(_ controller: UsersController, newLeftBarButtonImageName: String) { guard let newLeftImage = UIImage(named: newLeftBarButtonImageName) else { return } let newLeftButton = UIBarButtonItem(image: newLeftImage, style: .done, target: self, action: #selector(leftAction)) self.navigationItem.leftBarButtonItem = newLeftButton } }
方案三:直接获取控制器引用(不推荐)
通过控制器层级直接获取TabViewController实例,实现简单但耦合度极高,仅适合快速测试或简单场景。
在UsersController的handleLongPress方法中添加:
else if (longPressGesture.state == UIGestureRecognizer.State.began) { print("Long press on row, at \(indexPath!.row)") // 直接获取TabViewController实例 if let tabVC = self.tabBarController as? TabViewController { guard let newLeftImage = UIImage(named: "selectedBackButton") else { return } let newLeftButton = UIBarButtonItem(image: newLeftImage, style: .done, target: tabVC, action: #selector(tabVC.leftAction)) tabVC.navigationItem.leftBarButtonItem = newLeftButton } if !previousIndexPath.isEmpty { } }
内容的提问来源于stack exchange,提问作者Willian M.
相关产品推荐
相关产品推荐

