iOS 9/10下UITabBar Push转场时textView布局异常问题求助
解决iOS 9/10中Push Segue导致底部TextView布局跳动的问题
看起来你遇到的是iOS 9和10的一个已知系统bug——当使用hidesBottomBarWhenPushed推送新控制器时,源控制器的TabBar会在转场动画开始前短暂隐藏,导致依赖底部布局的控件(比如你的自定义TextView)出现位置跳动,这个问题在iOS 11中已经被苹果修复了。
下面给你两种可行的解决方案:
方案一:替代hidesBottomBarWhenPushed,手动控制TabBar显示/隐藏
放弃使用系统的hidesBottomBarWhenPushed属性,改为在目标控制器中手动控制TabBar的显示状态,这样可以避免源控制器的布局被意外干扰:
在你的PostViewController中添加以下代码:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 进入时隐藏TabBar tabBarController?.tabBar.isHidden = true } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 离开时恢复TabBar显示 tabBarController?.tabBar.isHidden = false }
然后移除源控制器中prepare(for:sender:)里设置hidesBottomBarWhenPushed的代码即可。这种方法最直接,也不会触发系统的布局bug。
方案二:保留hidesBottomBarWhenPushed,通过过渡协调器修复布局跳动
如果你必须使用hidesBottomBarWhenPushed,可以利用UIViewControllerTransitionCoordinator监听转场过程,临时调整TextView的约束来抵消TabBar短暂隐藏带来的布局变化:
假设你的TextView底部约束是一个IBOutlet(比如叫textViewBottomConstraint,常量为0,绑定到superView底部),在源控制器中添加以下代码:
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 仅处理目标为previewVC的push转场 guard let coordinator = transitionCoordinator, let tabBarHeight = tabBarController?.tabBar.frame.height else { return } coordinator.animate(alongsideTransition: { [weak self] _ in // 转场过程中,将TextView底部约束临时设置为TabBar的高度,抵消布局偏移 self?.textViewBottomConstraint.constant = tabBarHeight self?.view.layoutIfNeeded() }, completion: { [weak self] _ in // 转场完成后恢复原约束 self?.textViewBottomConstraint.constant = 0 self?.view.layoutIfNeeded() }) }
补充说明
- 这个bug的核心原因是iOS 9/10在处理
hidesBottomBarWhenPushed时,会先修改源控制器的TabBar状态再执行转场动画,导致AutoLayout触发不必要的布局更新;iOS 11中苹果调整了这个逻辑,所以不会出现问题。 - 如果你使用的是其他类型Segue(比如modal),因为不会触发TabBar的隐藏逻辑,所以自然不会出现布局跳动。
内容的提问来源于stack exchange,提问作者Codetard
相关产品推荐
相关产品推荐

