You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

长按后修改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)—— 低耦合

通过系统通知中心实现跨控制器事件传递,适合无直接关联的控制器场景。

  1. 在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)
}
  1. 在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)—— 类型安全

通过自定义协议实现控制器间强类型通信,适合明确层级关系的场景,可读性和可维护性更高。

  1. 定义代理协议
    在UsersController外部定义协议:
protocol UsersControllerLongPressDelegate: AnyObject {
    /// 长按触发时调用,可传递参数
    func usersControllerDidTriggerLongPress(_ controller: UsersController, newLeftBarButtonImageName: String)
}
  1. 修改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 {
            }
        }
        
        // 原有代码...
    }
}
  1. 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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 16:46:17