带居中UIButton的自定义TabBarController隐藏TabBar时按钮未同步隐藏的问题
自定义TabBar中心按钮同步显隐 & 底部Toolbar位置适配
问题背景
开发实现了带居中凸起按钮的自定义TabBarController,在需要隐藏TabBar的二级页面,仅对系统TabBar本体做了隐藏处理,自定义的中心UIButton没有同步隐藏,悬浮在页面上破坏布局;同时二级页面展示底部Toolbar时,位置不符合预期,和TabBar隐藏后的布局逻辑不匹配。
效果参考


现有实现代码
自定义TabBarController核心逻辑
let addButton = UIButton(frame: CGRect(x: 0, y: 0, width: 60, height: 60)) // MARK: - 生命周期 override func viewDidLoad() { super.viewDidLoad() self.delegate = self self.setupTabBar() self.setupAddButton() } // MARK: - 布局配置 private func setupTabBar() { let sectionTabNavigationController = createNavController( vc: MSMainCatalogVC(), title: NSLocalizedString("Catalog", comment: ""), image: UIImage(systemName: "text.justify")) let recentTabNavigationController = createNavController( vc: MSNotesTableVC(), title: NSLocalizedString("Recent", comment: ""), image: UIImage(systemName: "clock")) viewControllers = [recentTabNavigationController, sectionTabNavigationController] } private func createNavController(vc: UIViewController, title: String, image: UIImage?) -> UINavigationController { let navController = UINavigationController(rootViewController: vc) navController.tabBarItem.title = title if let image = image { navController.tabBarItem.image = image } return navController } private func setupAddButton() { var addButtonFrame = addButton.frame addButtonFrame.origin.y = self.view.bounds.height - self.tabBar.bounds.height * 2 addButtonFrame.origin.x = view.bounds.width/2 - addButtonFrame.size.width/2 addButton.frame = addButtonFrame view.addSubview(addButton) addButton.setImage(UIImage(systemName: "plus"), for: .normal) addButton.backgroundColor = .systemGray6 addButton.tintColor = UIColor.systemGray2 addButton.layer.borderColor = UIColor.systemGray2.cgColor addButton.layer.borderWidth = 1 addButton.layer.cornerRadius = 30 addButton.addTarget(self, action: #selector(pressCenterButton(sender:)), for: .touchUpInside) view.layoutIfNeeded() } // MARK: - 交互事件 @objc private func pressCenterButton(sender: UIButton) { // 点击添加按钮弹出功能选择弹窗 MSAddAlert.shared.show(for: self, button1Title: NSLocalizedString("Make photo", comment: ""), button2Title: NSLocalizedString("Select photo", comment: ""), button3Title: NSLocalizedString("Make note", comment: ""), button4Title: NSLocalizedString("Select file", comment: ""), button1Action: self.makePhoto, button2Action: self.addPhoto, button3Action: self.goToAddNoteVC, button4Action: nil) } private func goToAddNoteVC() { self.selectedViewController?.show(MSAddNoteVC(), sender: nil) }
二级页面TabBar隐藏逻辑
private func setupBars() { self.navigationItem.title = self.title ?? NSLocalizedString("New note", comment: "") self.tabBarController?.tabBar.alpha = 0 self.navigationController?.setToolbarHidden(false, animated: true) if #available(iOS 14.0, *) { self.setToolbarItems([self.cancelButton, UIBarButtonItem(systemItem: .flexibleSpace), self.saveButton], animated: true) } else { // 低版本iOS适配逻辑 } }
待解决问题
- 如何实现自定义中心添加按钮跟随TabBar的显示/隐藏逻辑同步切换状态,避免按钮悬浮残留
- 如何调整布局逻辑,让页面底部Toolbar放置在正确的位置,适配TabBar隐藏后的页面布局
解决方案
中心按钮与TabBar同步显隐
- 调整按钮的添加层级:不要将中心按钮加在TabBarController的根视图上,改为添加为TabBar的子视图。这样按钮会和TabBar绑定显示层级,TabBar的alpha、isHidden属性变化时,子视图会同步生效,避免手动管理状态不同步
对应修改:将
view.addSubview(addButton)替换为tabBar.addSubview(addButton),同时将按钮的frame计算逻辑从基于整个controller视图bounds,改为基于tabBar的bounds计算凸起位置,保证按钮位置不受外层视图布局变化影响 - 替换TabBar隐藏的实现方式:不要在二级页面手动设置
tabBar.alpha = 0,统一使用系统提供的hidesBottomBarWhenPushed属性管理显隐:在需要隐藏TabBar的二级页面viewDidLoad方法中设置self.hidesBottomBarWhenPushed = true,该属性会自动触发TabBar及其所有子视图的隐藏动画,从根源上避免按钮残留的问题 - 如果需要实现滚动时TabBar渐变的效果,可以在自定义TabBarController中监听TabBar的alpha值变化,同步设置addButton的alpha值,保证两个视图的透明度始终一致
修正底部Toolbar的位置
- 移除二级页面手动设置
tabBar.alpha = 0的代码后,Toolbar的位置会由iOS系统布局引擎自动计算:当hidesBottomBarWhenPushed生效、TabBar完全隐藏时,Toolbar会自动贴到安全区底部;当TabBar处于显示状态时,Toolbar会自动排布在TabBar上方,不需要手动调整frame - 排查是否存在手动修改安全区边距的代码,恢复导航控制器的默认布局逻辑:避免在二级页面手动修改
self.additionalSafeAreaInsets的底部值,iOS会自动根据底部展示的TabBar、Toolbar高度,计算对应的内容安全区高度,不需要手动干预 - 切换为
hidesBottomBarWhenPushed管理TabBar显隐后,系统会自动处理转场过程中的布局动画,不会再出现Toolbar和中心按钮错位偏移的问题
内容的提问来源于stack exchange,提问作者Darya
相关产品推荐
相关产品推荐

