使用 hidesBottomBarWhenPushed 的推送动画期间工具栏定位不正确
Toolbar incorrectly positioned during push animation with hidesBottomBarWhenPushed
我有一个使用 Tabbar 进行基本导航的应用程序。我想从 Tabbar 的一个屏幕进入另一个显示工具栏而不是 Tabbar 的屏幕和顶部的后退导航项。
最好的方法是什么?如果我使用 "Hide Bottom Bar on Push"(又名 hidesBottomBarWhenPushed)并向屏幕添加一个工具栏,我可以看到在将工具栏放置在屏幕底部之前移除 Tabbar 的动画。
问题示例
这是我的解决方案,
在具有 tabbar 的第一个视图 控制器中执行此操作
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "someSegue" {
if let secondVC = segue.destinationViewController as? InfoTableViewController {
secondVC.hidesBottomBarWhenPushed = true
}
}
}
我也需要这个,因为我的 工具栏 会重新出现在第一个 VC。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.toolbarHidden = true
}
要停止 工具栏 的淡入淡出动画,所以我在 第二个 VC 中使用了它
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.toolbarHidden = false
}
纯故事板解决方案
如果您指的是推送过渡动画期间工具栏出现在标签栏上方的问题,我可以通过调整情节提要中工具栏上的自动布局约束来解决此问题(手动将其添加到您的视图控制器;如果您使用的是 UITableViewController
或 UICollectionViewController
并且无法执行此操作,请参阅我的其他答案):
添加约束以将到底部布局指南的距离设置为零:
双击该约束进行编辑,并将第一项设置为底部(它将是顶部 默认。
大功告成!这将导致这样的效果:
Here's my sample project 表明它按预期工作。请注意,我没有更改任何代码,一切都在情节提要中。
UITableViewController
工具栏的解决方案(需要代码)
使用 this answer 中的代码,我能够实现相同的效果,但工具栏位于 table 视图的底部。
将此添加到您的 table 视图控制器:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setToolbarHidden:NO animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setToolbarHidden:YES animated:YES];
}
重要说明:将这些调用放在 viewWillAppear
和 viewWillDisappear
中而不是 viewDidLoad
中使得这更容易处理,因为它会起作用即使对于同一视图控制器的多次推送和弹出也很可靠,并且您不必在之前的视图控制器中进行清理。
并在情节提要中这样配置:
此外,在故事板或您的代码中为被推送的视图控制器启用按下时隐藏底栏。
然后您可以将工具栏按钮添加到情节提要中的工具栏。
构建并运行,你得到这样的效果:
从 Xcode 7 开始,纯 Storyboard 解决方案不再有效,因为 Xcode 不再允许您将 Bottom
属性分配给底部布局指南。
对于我的项目,我使用了以下设置:
- A
UITabBarController
作为初始视图控制器,进入
UINavigationController
,根 vc 设置为...
UIRegularViewController
,它应该表现正常,但会产生...
UISpecialViewController
,它应该隐藏标签栏并显示一个工具栏。此外,它应该隐藏状态栏、导航栏和点击时的工具栏。
这是我为实现这一目标所做的工作:
在情节提要中
UITabBarController
: 将标签栏半透明度设置为 NO
UISpecialViewController
:像这样设置模拟指标
- 状态栏:None
- 顶部栏:不透明导航栏
- 底部栏:不透明工具栏
像这样设置扩展边:
- 顶栏下:无
- 底栏下:是
- 在不透明条下:是
不要 将 UIToolBar 拖到 UISpecialViewController
中!
在实现中
// in UISpecialViewController.m
- (void)viewWillAppear:(BOOL)animated {
self.navigationController.toolbarHidden = NO;
self.navigationController.hidesBarsOnTap = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
self.navigationController.toolbarHidden = YES;
self.navigationController.hidesBarsOnTap = NO;
}
- (BOOL)prefersStatusBarHidden {
return self.navigationController.navigationBarHidden;
}
这里是 Demo Code.
这是结果:
其实UIKit已经配置了Toolbar和Tabbar在页面切换动画中的变化方式
我今天也遇到了这种情况,最后的解决方案让我很惊讶。
比如A页到B页,A页显示Tabbar,不显示Toolbar,B页不显示Toolbar,不显示Tabbar。
此时B需要将hidesBottomBarWhenPushed设置为true,这是必须的
然后,在两个ViewController的声明循环中,在A的viewWillDisappear和B的viewWillAppear中,如果设置了navigation controller setToolbarHidden,就会出现这个动画问题。
如果在A的viewDidDisappear和B的viewDidAppear中设置,问题就解决了。虽然工具栏会有延迟动画,但总比错动画好。
最后补充:
A、B生命周期函数调用顺序为:
- A - viewWillDisappear
- B - viewWillAppear
- A - viewDidDisappear
- B - viewDidAppear
这四种方法是交错的
使用 Xcode 12.4 iOS 14.4
对于那些为这个问题而苦苦挣扎并尝试上述解决方案但没有成功的人。
假设 A 仅带有 tabBar,B 仅显示工具栏
记得在B的init
里设置hidesBottomBarWhenPushed = true
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
hidesBottomBarWhenPushed = true
}
在 B 中实现以下这些。(无需在 A 中执行任何操作)
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.setToolbarHidden(true, animated: false)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
navigationController?.setToolbarHidden(false, animated: false)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.setToolbarHidden(true, animated: true)
}
就是这样了!!
p.s。如果你想从下往上移除工具栏动画然后添加这个
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
navigationController?.toolbar.layer.removeAnimation(forKey: "position")
}
我有一个使用 Tabbar 进行基本导航的应用程序。我想从 Tabbar 的一个屏幕进入另一个显示工具栏而不是 Tabbar 的屏幕和顶部的后退导航项。
最好的方法是什么?如果我使用 "Hide Bottom Bar on Push"(又名 hidesBottomBarWhenPushed)并向屏幕添加一个工具栏,我可以看到在将工具栏放置在屏幕底部之前移除 Tabbar 的动画。
问题示例
这是我的解决方案,
在具有 tabbar 的第一个视图 控制器中执行此操作
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "someSegue" {
if let secondVC = segue.destinationViewController as? InfoTableViewController {
secondVC.hidesBottomBarWhenPushed = true
}
}
}
我也需要这个,因为我的 工具栏 会重新出现在第一个 VC。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.toolbarHidden = true
}
要停止 工具栏 的淡入淡出动画,所以我在 第二个 VC 中使用了它
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.toolbarHidden = false
}
纯故事板解决方案
如果您指的是推送过渡动画期间工具栏出现在标签栏上方的问题,我可以通过调整情节提要中工具栏上的自动布局约束来解决此问题(手动将其添加到您的视图控制器;如果您使用的是 UITableViewController
或 UICollectionViewController
并且无法执行此操作,请参阅我的其他答案):
添加约束以将到底部布局指南的距离设置为零:
双击该约束进行编辑,并将第一项设置为底部(它将是顶部 默认。
大功告成!这将导致这样的效果:
Here's my sample project 表明它按预期工作。请注意,我没有更改任何代码,一切都在情节提要中。
UITableViewController
工具栏的解决方案(需要代码)
使用 this answer 中的代码,我能够实现相同的效果,但工具栏位于 table 视图的底部。
将此添加到您的 table 视图控制器:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setToolbarHidden:NO animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setToolbarHidden:YES animated:YES];
}
重要说明:将这些调用放在 viewWillAppear
和 viewWillDisappear
中而不是 viewDidLoad
中使得这更容易处理,因为它会起作用即使对于同一视图控制器的多次推送和弹出也很可靠,并且您不必在之前的视图控制器中进行清理。
并在情节提要中这样配置:
此外,在故事板或您的代码中为被推送的视图控制器启用按下时隐藏底栏。
然后您可以将工具栏按钮添加到情节提要中的工具栏。
构建并运行,你得到这样的效果:
从 Xcode 7 开始,纯 Storyboard 解决方案不再有效,因为 Xcode 不再允许您将 Bottom
属性分配给底部布局指南。
对于我的项目,我使用了以下设置:
- A
UITabBarController
作为初始视图控制器,进入 UINavigationController
,根 vc 设置为...UIRegularViewController
,它应该表现正常,但会产生...UISpecialViewController
,它应该隐藏标签栏并显示一个工具栏。此外,它应该隐藏状态栏、导航栏和点击时的工具栏。
这是我为实现这一目标所做的工作:
在情节提要中
UITabBarController
: 将标签栏半透明度设置为 NO
UISpecialViewController
:像这样设置模拟指标
- 状态栏:None
- 顶部栏:不透明导航栏
- 底部栏:不透明工具栏
像这样设置扩展边:
- 顶栏下:无
- 底栏下:是
- 在不透明条下:是
不要 将 UIToolBar 拖到 UISpecialViewController
中!
在实现中
// in UISpecialViewController.m
- (void)viewWillAppear:(BOOL)animated {
self.navigationController.toolbarHidden = NO;
self.navigationController.hidesBarsOnTap = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
self.navigationController.toolbarHidden = YES;
self.navigationController.hidesBarsOnTap = NO;
}
- (BOOL)prefersStatusBarHidden {
return self.navigationController.navigationBarHidden;
}
这里是 Demo Code.
这是结果:
其实UIKit已经配置了Toolbar和Tabbar在页面切换动画中的变化方式
我今天也遇到了这种情况,最后的解决方案让我很惊讶。
比如A页到B页,A页显示Tabbar,不显示Toolbar,B页不显示Toolbar,不显示Tabbar。
此时B需要将hidesBottomBarWhenPushed设置为true,这是必须的
然后,在两个ViewController的声明循环中,在A的viewWillDisappear和B的viewWillAppear中,如果设置了navigation controller setToolbarHidden,就会出现这个动画问题。
如果在A的viewDidDisappear和B的viewDidAppear中设置,问题就解决了。虽然工具栏会有延迟动画,但总比错动画好。
最后补充: A、B生命周期函数调用顺序为:
- A - viewWillDisappear
- B - viewWillAppear
- A - viewDidDisappear
- B - viewDidAppear
这四种方法是交错的
使用 Xcode 12.4 iOS 14.4
对于那些为这个问题而苦苦挣扎并尝试上述解决方案但没有成功的人。
假设 A 仅带有 tabBar,B 仅显示工具栏
记得在B的init
里设置hidesBottomBarWhenPushed = true
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
hidesBottomBarWhenPushed = true
}
在 B 中实现以下这些。(无需在 A 中执行任何操作)
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.setToolbarHidden(true, animated: false)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
navigationController?.setToolbarHidden(false, animated: false)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.setToolbarHidden(true, animated: true)
}
就是这样了!!
p.s。如果你想从下往上移除工具栏动画然后添加这个
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
navigationController?.toolbar.layer.removeAnimation(forKey: "position")
}