【发布时间】:2017-02-27 06:40:56
【问题描述】:
我这几天一直在解决以下问题。我在文档中找不到关于我做错了什么的任何内容。我已经爬过调试器并将各种信息转储到控制台,但无法弄清楚如何修复我所看到的内容。
我的顶级视图控制器是 UINavigationController 的子类。这包含 UIPageViewController 的子类,它将用于可视化我的数据。它还包含 UITableViewController 的子类,用于设置应用程序设置。这个“选项”视图通过 push segue “链接”到页面视图控制器。至此,一切正常。
当我想区分各种可视化数据的方式(页面视图控制器中的水平滚动)和引入选项视图之间的视觉转换时,问题就开始了。因此,我创建了一个自定义动画,以从屏幕顶部“拉伸”选项控制器(推送时)或将选项控制器“卷起”到屏幕顶部(弹出时)。我使用 navigationController:animationControllerFor:operation:from:to: 方法在导航控制器上设置了这个动画。
在显示选项控制器之前,设备旋转期间一切似乎都正常。 显示/关闭选项控制器后,数据可视化控制器的布局在旋转过程中发生故障。它以选项控制器被关闭时设备所在的方向正确显示,但在相反方向上播放不正确。
导航控制器(或者可能是页面视图控制器)似乎忘记了如何处理状态、导航和工具栏的高度。
以下显示的调试屏幕截图说明了 5s 模拟器上的问题
- 初始状态。请注意,内容视图(红色)在状态、导航和工具栏的下方。
- 将方向旋转为水平。到目前为止一切正常。调试控制台显示视图正在“旋转”到 (568x212) 的大小、状态、导航和工具栏的前后高度、屏幕大小、框架矩形和图层位置。我这里没有展示,但是图层锚点永远不会从 (0.5, 0.5) 改变。
请注意,目标旋转大小是使用以下规则设置的:
- rot_width(568) = old_frame_height(460) + sum_of_bar_heights(108)
- rot_height(212) = old_frame_width(320) - sum_of_bar_heights(108)
使用以下规则设置生成的帧大小:
- new_frame_width(568) = rot_width(568)
- new_frame_height(256) = rot_height(212) + change_in_bar_height(108-64)
结果帧原点 (0,64) 与屏幕顶部的偏移量为状态栏 (20) 和导航栏 (44) 之和。
- 将方向旋转回垂直。再次,一切正常。调试控制台为“反向”旋转添加了与上述相同的信息。旋转大小和生成的帧大小遵循与上述相同的规则。
- 使用自定义动画将选项编辑器控制器视图推送到导航堆栈。调试控制台为上面的(当前不可见的)内容视图添加了与上面相同的信息。请注意,没有任何变化。
- 使用自定义动画将选项编辑器控制器视图从导航堆栈中弹出。上面的内容视图返回视图。调试控制台添加与上面相同的信息。同样,一切都没有改变。
注意,堆叠顺序与选项编辑器可见之前不同。
使用默认转换动画器时,此堆栈重新排序不成立(通过从 pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted 返回 nil)
- 重复第 1 步。这就是事情的发展方向“wonky”。内容视图不再紧贴导航和工具栏。调试控制台显示 进入 旋转的所有内容都与第 1 步中的相同。
BUT,轮换的结果和第1步不同。规则好像变了。生成的框架大小不再根据状态、导航和工具栏高度的变化进行调整,并且框架原点与旋转之前的状态相比没有变化。
- 重复第 2 步。似乎一切都已修复,但这只是因为它正在按照新的调整大小规则进行播放。
这里显示了我的动画师类(完整的,除了用于生成上面显示的调试信息的探针):
class OptionsViewAnimator: NSObject, UIViewControllerAnimatedTransitioning
{
var type : UINavigationControllerOperation
init(_ type : UINavigationControllerOperation)
{
self.type = type
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval
{
return 0.35
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
{
if self.type == .push { showOptions(using:transitionContext) }
else if self.type == .pop { hideOptions(using:transitionContext) }
}
func showOptions(using context: UIViewControllerContextTransitioning)
{
let src = context.viewController(forKey: .from)!
let srcView = context.view(forKey: .from)!
let dstView = context.view(forKey: .to)!
var dstEnd = context.finalFrame(for: context.viewController(forKey: .to)!)
let barHeight = (src.navigationController?.toolbar.frame.height) ?? 0.0
dstEnd.size.height += barHeight
dstView.frame = dstEnd
dstView.layer.position = dstEnd.origin
dstView.layer.anchorPoint = CGPoint(x:0.0,y:0.0)
dstView.transform = dstView.transform.scaledBy(x: 1.0, y: 0.01)
UIApplication.shared.keyWindow!.insertSubview(dstView, aboveSubview: srcView)
UIView.animate(withDuration: 0.35, animations:
{
dstView.transform = .identity
}
) {
(finished)->Void in
context.completeTransition( !context.transitionWasCancelled )
}
}
func hideOptions(using context: UIViewControllerContextTransitioning)
{
let dst = context.viewController(forKey: .to)!
let srcView = context.view(forKey: .from)!
let dstView = context.view(forKey: .to)!
let dstEnd = context.finalFrame(for: context.viewController(forKey: .to)!)
dstView.frame = dstEnd
srcView.layer.position = dstEnd.origin
srcView.layer.anchorPoint = CGPoint(x:0.0,y:0.0)
srcView.transform = .identity
UIApplication.shared.keyWindow!.insertSubview(dstView, belowSubview: srcView)
UIView.animate(withDuration: 0.35, animations:
{
srcView.transform = srcView.transform.scaledBy(x: 1.0, y: 0.01)
}
) {
(finished)->Void in
context.completeTransition( !context.transitionWasCancelled )
}
}
}
感谢您的任何/所有帮助。 麦克
【问题讨论】:
-
只是好奇是否没有人知道答案,或者我的问题是否存在根本性的问题而没有人参与。
-
给我一点,我会试着权衡一下。这是一个非常高级的问题。我以前也遇到过,所以我去看看代码,看看问题。
-
请查看答案并让我知道它是否有效。如果是这样,请标记正确。干杯
标签: ios objective-c uinavigationcontroller transition ios-animations