在控制器转换期间动画化UINavigationController高度

4

我正在使用Swift设计一个iOS应用程序,但在控制器转换期间遇到了一些动画问题。具体来说,我已经实现了UINavigationControllerDelegate,以便在某个视图被推送时监听它。当这个视图被推送时,我想隐藏屏幕底部的一个栏。我的代码几乎完美地工作了,但每当我开始对导航控制器的高度进行动画处理时,当前视图(正在被移除的视图)会正确地动画化其高度,但是新的控制器被推入时已经具有了新的动画高度。为了让代码更加清晰,以下函数是从我的UINavigationControllerDelegate的willShow viewController函数中调用的:

func animatePlayerVisibility(_ visible: Bool) {

    if visible == showingPlayer {
        return
    }
    showingPlayer = visible

    let height: CGFloat = visible ? 56.0 : 0.0
    self.view.layoutIfNeeded()
    UIView.animate(withDuration: 0.35) {
        self.playerHeight.constant = height
        self.viewBottom.constant = height
        self.view.layoutIfNeeded()
    }
}

'playerHeight'是指播放器容器视图高度的一个IBOutlet约束。'viewBottom'也是一个IBOutlet约束,连接了顶部容器视图的底部与屏幕底部。实际上,只要这两个约束一起动画,它应该看起来很好。

为了帮助可视化这个图形错误,我编辑了这条线。

self.viewBottom.constant = height

为了

self.viewBottom.constant = height * 2.0

我已经创建了一个 imgur 相册,展示了实际错误行为的情况:http://imgur.com/a/znAim 如你所见,旧视图控制器在新控制器已经有新的动画大小时能正确地进行动画。
这是故事板的布局:Storyboard 任何帮助都将不胜感激。我一直在尝试修复这个问题,但一直没有成功。
编辑:动画的视图没有应用 *2 的情况下:https://imgur.com/a/2a5Sw

我不确定我是否正确理解了你的问题,但我会使用UIViewControllerAnimatedTransitioning:隐藏您正在过渡的视图控制器的导航栏,重新创建它并将其添加到上下文中,根据需要动画其高度,当动画结束时,从上下文中删除它并取消隐藏目标控制器的导航栏。在用户眼中,这一切都将看起来无缝。 - cyril
因此,我并不打算对导航栏进行任何操作,而且由于我只是将其推入到一个导航控制器中,所以新视图没有导航栏。 我遇到的问题是,在将视图推送到UINavigationController之前,如果UINavigationController的高度已经被动画化,则正在推送到导航控制器的视图的高度将具有未来的动画化高度,而不是受其包含的导航控制器底部的限制。 我不会从这个故事板转换,只是将一个视图推送到其中的导航控制器中。 - Jtvd78
2个回答

0

我创建了一个不错的小样例项目,你可以在这里找到它!

可能有很多问题出现了,因为我没有亲自检查过你的项目,而且我的示例中组织方式可能非常不同,但希望你能理解。我认为重要的是,在storyboard中添加了一个约束条件,将navigationController的容器添加到根viewController的底部。当我进行动画时,我不会调整此容器的高度。


我只想澄清一下,我并不是从一个故事板转移到另一个故事板。我只是将一个视图推送到UINavigationController中。我知道我的故事板不太寻常,因为我以前是在Android上开发的,但我认为这个问题与故事板本身无关,而只是UINavigationController的默认行为。我已经更新了主贴,附上了一个非夸张版本的动画。感谢你迄今为止的帮助。 - Jtvd78
嗯,第二个例子确实有点帮助,现在我注意到你的根控制器是一个pageController。让我看看能否快速举个例子,稍后再回来检查。 - mmd1080
@Jtvd78 请告诉我你是否有时间检查这个,想知道你的想法。 - mmd1080
1
嘿,非常抱歉没有回复你,但我真的很感激您提供的示例代码。我看到您如何设置它,而且它绝对是有意义的。我实际上正在出国旅行,所以直到现在才有时间查看响应。我认为它很好,并且当我开始根据您的示例工作时,我一定会让您知道。再次感谢。 - Jtvd78
我成功解决了最后的问题,方法是对 UINavigationController 进行子类化并覆盖 pushViewController。在 pushViewController 中,我将传入的控制器包裹在 'ContainerController' 中,该容器控制器中只有一个 UIView,然后我调整大小。现在,每个 ViewController 都不需要实现与 mini-player 相关的任何内容。 - Jtvd78
显示剩余4条评论

0

你有没有考虑不使用UINavigationController?也许使用ChildViewControllers机制会更容易。然后,你可以使用强大的自动布局,并对动画(在你的情况下是高度)拥有更多控制权。

关于此更多信息在这里


你觉得你能提供更详细的信息,说明你会如何处理这个问题吗?大多数关于此的指南都是针对非默认外观的转换行为,但我打算让过渡仍然看起来“原样”。 - Jtvd78
你的意思是什么,“stock”? - Kamil Harasimowicz
传入的视图只是从左向右滑动。现在我想做的就是改变UINavigationController的高度,但当我在转换之前激活高度动画时,传入的视图已经具有新的高度,即使动画尚未完成。我不需要任何花哨的过渡效果。 - Jtvd78
抱歉,我误解了你的问题。我更新了我的答案,也许可以帮到你。 - Kamil Harasimowicz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接