Swift中能否对父视图控制器的视图执行动画?自定义TabBar隐藏需求
解决方案:子控制器控制父控制器自定义TabBar的显示隐藏
当然可行!我来给你分享几种Swift开发里处理这类父子控制器通信的常用方案,都能实现你要的TabBar滑出/滑入效果:
1. 代理模式(最推荐,解耦性强)
这是父子组件通信的标准方案,能让代码结构更清晰,后期维护也方便。
步骤:
- 首先在子控制器里定义一个协议,声明需要通知父控制器的行为:
protocol ChildFullScreenDelegate: AnyObject { // 传入是否需要隐藏TabBar的状态 func childDidToggleFullScreen(_ isFullScreen: Bool) }
- 在子控制器里添加一个弱引用的代理属性(用
weak避免循环引用):
class SomeChildViewController: UIViewController { weak var fullScreenDelegate: ChildFullScreenDelegate? // 当需要全屏时调用这个方法 func enterFullScreen() { fullScreenDelegate?.childDidToggleFullScreen(true) } // 退出全屏时调用 func exitFullScreen() { fullScreenDelegate?.childDidToggleFullScreen(false) } }
- 在根控制器(父VC)里遵守这个协议,实现协议方法,处理TabBar的动画:
class RootViewController: UIViewController, ChildFullScreenDelegate { // 假设你的自定义TabBar和它的底部约束是这样的 @IBOutlet weak var customTabBar: UIView! @IBOutlet weak var tabBarBottomConstraint: NSLayoutConstraint! // 添加子控制器的时候,记得设置代理 func addChildControllers() { let childVC = SomeChildViewController() childVC.fullScreenDelegate = self // ... 常规添加子控制器的代码:addChild、view添加到容器、didMove } // 实现代理方法 func childDidToggleFullScreen(_ isFullScreen: Bool) { UIView.animate(withDuration: 0.3) { // 滑出屏幕就把约束constant设为TabBar的高度,恢复就设为0 self.tabBarBottomConstraint.constant = isFullScreen ? self.customTabBar.bounds.height : 0 self.view.layoutIfNeeded() } } }
2. 通知中心(快速实现,适合简单场景)
如果不想写代理的协议,用通知中心也是个快捷方式,不过要注意内存泄漏问题。
步骤:
- 在根控制器的
viewDidLoad里监听自定义通知:
class RootViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 监听隐藏TabBar的通知 NotificationCenter.default.addObserver(self, selector: #selector(hideTabBar), name: NSNotification.Name("HideCustomTabBar"), object: nil) // 监听显示TabBar的通知 NotificationCenter.default.addObserver(self, selector: #selector(showTabBar), name: NSNotification.Name("ShowCustomTabBar"), object: nil) } @objc func hideTabBar() { UIView.animate(withDuration: 0.3) { self.tabBarBottomConstraint.constant = self.customTabBar.bounds.height self.view.layoutIfNeeded() } } @objc func showTabBar() { UIView.animate(withDuration: 0.3) { self.tabBarBottomConstraint.constant = 0 self.view.layoutIfNeeded() } } // 记得在销毁时移除监听,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) } }
- 在子控制器需要全屏/退出全屏时,发送对应的通知:
// 进入全屏时发送隐藏通知 NotificationCenter.default.post(name: NSNotification.Name("HideCustomTabBar"), object: nil) // 退出全屏时发送显示通知 NotificationCenter.default.post(name: NSNotification.Name("ShowCustomTabBar"), object: nil)
3. 直接获取父控制器引用(简单但耦合性高)
如果你的项目结构比较简单,也可以直接在子控制器里获取父控制器的引用,然后直接操作TabBar,但这种方式耦合性高,后期根控制器结构变化容易出问题,不推荐复杂项目使用。
示例代码:
class SomeChildViewController: UIViewController { func enterFullScreen() { // 强制转换为你的根控制器类型 guard let rootVC = parent as? RootViewController else { return } UIView.animate(withDuration: 0.3) { rootVC.tabBarBottomConstraint.constant = rootVC.customTabBar.bounds.height rootVC.view.layoutIfNeeded() } } }
不管用哪种方案,核心都是让子控制器把“需要全屏”的信号传递给父控制器,再由父控制器来处理TabBar的动画——毕竟父控制器才是TabBar的拥有者,由它来操作最安全。
内容的提问来源于stack exchange,提问作者KLD
相关产品推荐
相关产品推荐

