Swift中隐藏tabBar时如何同步隐藏通知红点?
嘿,这个问题我之前帮好几个开发者捋清楚过,核心就是把tabBar的显示状态和小红点(badge)的显示状态绑定起来就行,下面给你两种实用的方案,你可以根据自己的项目架构来选:
方案一:自定义UITabBarController(最推荐,逻辑集中好维护)
这种方式把所有和tabBar、badge相关的逻辑都收拢在子类里,后期改需求也方便:
- 先给
UITabBarController做个自定义子类,比如叫CustomTabBarController - 在子类里写一个统一管理badge显示/隐藏的方法,这里要注意保存原来的badge值,不然隐藏后再回来就丢了:
func updateBadgeVisibility() { guard let tabBarItems = tabBar.items else { return } // 判断当前tabBar是否需要显示(这里可以根据tabBar.isHidden,或者你自己维护的状态) let shouldShowBadges = !tabBar.isHidden for item in tabBarItems { let badgeKey = "SavedBadge_\(item.tag)" if shouldShowBadges { // 恢复之前保存的badge值 item.badgeValue = UserDefaults.standard.string(forKey: badgeKey) ?? item.badgeValue } else { // 先保存当前badge值,再清空显示 UserDefaults.standard.set(item.badgeValue, forKey: badgeKey) item.badgeValue = nil } } }
提示:如果你的badge值是从服务器接口或本地数据库实时获取的,也可以直接从数据源拉取恢复,不用存在UserDefaults里,这样更准确。
- 监听tabBar的显示状态变化,比如你常用
hidesBottomBarWhenPushed = true来隐藏tabBar的话,让自定义的tabBarController充当导航控制器的代理,在导航栈变化时自动更新badge:
extension CustomTabBarController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { // 这里会自动处理push/pop时的tabBar显示状态 DispatchQueue.main.async { self.updateBadgeVisibility() } } }
别忘了在viewDidLoad里设置代理:
override func viewDidLoad() { super.viewDidLoad() navigationController?.delegate = self }
方案二:通知+全局状态(适合不想改tabBarController的情况)
如果你的项目已经用了系统的UITabBarController,不想改子类,可以用通知来触发badge的显示/隐藏:
- 先定义一个通知名称:
extension Notification.Name { static let tabBarVisibilityChanged = Notification.Name("TabBarVisibilityChanged") }
- 在tabBar所在的控制器(比如每个tab的根VC,或者直接在UITabBarController的分类里)添加监听:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(updateBadgeStatus), name: .tabBarVisibilityChanged, object: nil) } @objc private func updateBadgeStatus(_ notification: Notification) { guard let isTabBarHidden = notification.userInfo?["isHidden"] as? Bool, let tabBarItems = tabBar.items else { return } for item in tabBarItems { let saveKey = "TabBadge_\(item.tag)" if isTabBarHidden { UserDefaults.standard.set(item.badgeValue, forKey: saveKey) item.badgeValue = nil } else { item.badgeValue = UserDefaults.standard.string(forKey: saveKey) } } }
- 当你要隐藏tabBar时(比如在push的VC的
viewWillAppear里)发送通知:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) hidesBottomBarWhenPushed = true NotificationCenter.default.post(name: .tabBarVisibilityChanged, object: nil, userInfo: ["isHidden": true]) }
- 当返回带tabBar的页面时(比如在tab根VC的
viewWillAppear里)发送恢复通知:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.post(name: .tabBarVisibilityChanged, object: nil, userInfo: ["isHidden": false]) }
额外注意点
UITabBarItem的badgeValue是字符串类型,如果你的通知数是数字,记得转成字符串再设置- 如果是present弹窗隐藏tabBar的情况,在present前发送隐藏通知,dismiss后发送恢复通知就行
- 记得在控制器销毁时移除通知监听(方案二需要):
deinit { NotificationCenter.default.removeObserver(self) }
内容的提问来源于stack exchange,提问作者KevinB
相关产品推荐
相关产品推荐

