在使用 hidesBottomBarWhenPushed 进行推送动画期间工具栏定位不正确

Posted

技术标签:

【中文标题】在使用 hidesBottomBarWhenPushed 进行推送动画期间工具栏定位不正确【英文标题】:Toolbar incorrectly positioned during push animation with hidesBottomBarWhenPushed 【发布时间】:2015-03-29 20:13:49 【问题描述】:

我有一个使用标签栏进行基本导航的应用程序。从 Tabbar 的一个屏幕中,我想输入另一个显示工具栏而不是 Tabbar 的屏幕和顶部的后退导航项。

最好的方法是什么?如果我使用“Hide Bottom Bar on Push”(又名 hidesBottomBarWhenPushed)并向屏幕添加工具栏,我可以看到在工具栏放置在屏幕底部之前删除 Tabbar 的动画。

【问题讨论】:

试图自己解决这个问题。你整理了吗?赏金时间!! 这是你要找的效果吗:i.imgur.com/eACSkMS.gif? 这就是我想要的效果,我正要创建一个问题的gif。但我的解决方案给出了你展示的效果。 @DogCoffee 我想出了一个纯故事板解决方案,我会写一个答案并发布。 【参考方案1】:

带有工具栏的UITableViewController 的解决方案(需要代码)

使用来自this answer 的代码,我能够实现相同的效果,但工具栏位于表格视图的底部。

将此添加到您的表格视图控制器:

- (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];

重要提示:将这些调用放在 viewWillAppearviewWillDisappear 而不是 viewDidLoad 中可以更容易处理,因为即使对于同一视图的多次推送和弹出,它也能可靠地工作控制器,您不必在之前的视图控制器中清理它。

并在情节提要中像这样配置它:

此外,在情节提要或代码中启用在推送时隐藏底栏,以便推送视图控制器。

然后您可以将工具栏按钮添加到情节提要的工具栏中。

构建并运行,你会得到这样的效果:

Here's a complete sample project demonstrating this.

【讨论】:

我试过了,但我的应用程序没有工作,仍然在第二个 VC 上显示工具栏的动画。 @DogCoffee 尝试查看示例项目并比较设置。我从默认模板创建它,只更改了此处列出的内容。 你用什么来创建你的 GIF?我创建的 GIF 不太好。 我是这样做的,唯一的区别是我选择使用 self.navigationController?.setToolbarHidden(false, animated: false) 来避免向用户显示动画 在 10.2 Xcode 8.2.1 上仍然是一个问题。对我来说,似乎只发生在 Swift 项目中。这是唯一仍然有效的解决方案,其他大多数解决方案都没有任何效果或无法解决问题。【参考方案2】:

问题示例

这是我的解决方案,

在具有标签栏第一个视图控制器中执行此操作

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

【讨论】:

【参考方案3】:

纯故事板解决方案

如果您指的是在推送过渡动画期间工具栏出现在选项卡栏上方的问题,我可以通过调整情节提要中工具栏上的自动布局约束来解决此问题(手动将其添加到您的视图控制器;如果您使用的是 UITableViewControllerUICollectionViewController 并且不能这样做,请参阅我的其他答案):

添加约束以将到底部布局指南的距离设置为零:

双击该约束进行编辑,并将第一项设置为Bottom(默认为Top)。 p>

全部完成!这将产生如下效果:

Here's my sample project 证明了它按预期工作。请注意,我没有更改任何代码,一切都在故事板中。

【讨论】:

我已经看到了这个答案,但是如果您使用 UITableViewController,则无法向工具栏添加约束(当您在界面生成器中显示它时)...好吧,我还是不能。 @DogCoffee 我也找不到使用约束的方法,但它仍然可行,类似于您的答案,但避免在源视图控制器中进行清理(请参阅我的第二个答案)。 我发布了我的第一个答案(并将其分开),因为该问题没有提到正在使用的表格视图,并且标记为storyboard,所以我认为故事板解决方案可能更方便对于提问者而不是替代者。 Xcode 7 不再允许您将 Top to Bottom 更改为底部布局指南。【参考方案4】:

从 Xcode 7 开始,纯 Storyboard 解决方案不再起作用,因为 Xcode 不再允许您将 Bottom 属性分配给底部布局指南。

对于我的项目,我使用了以下设置:

UITabBarController 作为初始视图控制器,进入一个 UINavigationController,root vc 设置为... UIRegularViewController,应该正常运行,但会产生一个... UISpecialViewController,它应该隐藏标签栏,而是显示一个工具栏。此外,它应该隐藏状态栏、导航栏和点击工具栏。

这是我为实现这一目标所做的:

在故事板中

UITabBarController:将标签栏半透明设置为NO

UISpecialViewController:像这样设置模拟指标

状态栏:无 顶部栏:不透明导航栏 底栏:不透明的工具栏

像这样设置扩展边缘

在顶栏下:否 在底栏下:是 在不透明条下:是的

不要不要将 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。

这是结果:

【讨论】:

【参考方案5】:

其实UIKit已经在页面切换动画中配置了Toolbar和Tabbar如何变化。

我今天也和你有这种情况,最终的解决方案让我很惊讶。

比如页面A到页面B,页面A显示Tabbar,不显示Toolbar,页面B不显示Toolbar,也不显示Tabbar。

此时B需要设置hidesBottomBarWhenPushed为true,这是必须的。

那么,在两个ViewController的声明周期中,在A的viewWillDisappear和B的viewWillAppear中,如果设置导航控制器setToolbarHidden,就会出现这个动画问题。

如果在A的viewDidDisappear和B的viewDidAppear中设置,问题就解决了。虽然工具栏会有延迟的动画,但总比错误的动画好。

最后添加: A、B生命周期函数调用顺序为:

    A - viewWillDisappear B - viewWillAppear A - viewDidDisappear B - viewDidAppear

这四种方法是交错的。

【讨论】:

【参考方案6】:

使用 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)

就是这样!!

附言如果你想从下往上移除工具栏动画然后添加这个

override func viewDidLayoutSubviews() 
    super.viewDidLayoutSubviews()
    navigationController?.toolbar.layer.removeAnimation(forKey: "position")

【讨论】:

以上是关于在使用 hidesBottomBarWhenPushed 进行推送动画期间工具栏定位不正确的主要内容,如果未能解决你的问题,请参考以下文章

为啥在使用 unicode 时我不能在 :before :after 内容之后使用空格

在哪里使用 callable 以及在哪里使用 Runnable Interface?

在 Observable RxSwift 中使用 'asPromise()' 可以在 PromiseKit Promise 中使用吗?

可以在 SELECT 查询中使用 IF() 但不能在 UPDATE 中使用

使用 React,在使用 react-transition-group 时,在 StrictMode 中不推荐使用 findDOMNode 作为警告

在本地为 Django 使用 SQLite,在服务器上使用 Postgres