交互式关闭模态时出现故障
Glitch when interactively dismissing modal
在通过 UIPercentDrivenInteractiveTransition
实现模态视图控制器的交互式关闭(向下拖动模态应该关闭它)时,我们已经 运行 解决了这个问题。
设置:
- 设置
UIViewController
嵌入 UINavigationController
至少有一个按钮 UINavigationBar
- 模态呈现
UINavigationController
中嵌入的另一个 UIViewController
,至少有一个 UINavigationBar
中的按钮
- 设置
UIPanGestureRecognizer
模态呈现 UINavigationController
以驱动 UIPercentDrivenInteractiveTransition
- 将模态向下拖动 "holding" 按
UINavigationBar
上的点
问题:
缓慢向下拖动时,动画故障导致模态视图上下跳动
仅在 :
时出现故障
- 两个
UINavigationBar
都至少有一个按钮
- 你"hold"模态被点上
UINavigationBar
可以从 github repo 下载最小示例。
有人遇到过这样的问题吗?有什么解决方法吗?我们的设置有什么缺陷吗?
更新
问题已在 运行 上面的 iPhone 5 模拟器上用 iOS 9.3
、OSX 10.11.4
、Xcode [=26= 编译的项目进行了模拟].
更新 2
进一步调查表明,该问题可能不在动画中:出于某种原因,在给定设置中 pan.translationInView(view)
返回意外值,导致动画跳转。
部分解决方法
根据 Vladimir 的想法,我们通过覆盖 UINavigationBar
的 hitTest
方法部分解决了这个问题:
class DraggableNavigationBar: UINavigationBar {
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
guard let view = super.hitTest(point, withEvent: event) else { return nil }
if view is UIControl || pointIsInsideNavigationButton(point) {
return view
} else {
return nil
}
}
private func pointIsInsideNavigationButton(point: CGPoint) -> Bool {
return subviews
.filter { [=10=].frame.contains(point) }
.filter { String([=10=].dynamicType) == "UINavigationItemButtonView" }
.isEmpty == false
}
}
我没有完整的解决方案,但我能够将故障减少一定程度。我可以在 iPhone 5 秒内使用 iOS 9.3.2
[通过按住导航栏向下拖动屏幕]
重现此问题
问题似乎出在 DismissalAnimator
的 UIView.animateWithDuration
块中。通过注释掉延迟和选项,即将它们保持为默认值,您可以减少视图的跳跃。您也可以尝试检查获得最小跳跃的不同 UIViewAnimationOptions
。
UIView.animateWithDuration(0.3,
animations: {
dismissedView.frame = finalFrame
},
completion: { _ in
let didComplete = !transitionContext.transitionWasCancelled()
transitionContext.completeTransition(didComplete)
}
)
a question 似乎正在处理您面临的相同问题。并且响应从禁用自动布局,将 layoutIfNeeded
放入动画块 [尝试过,都没有用]。
非常有趣的故障。几天前我找到了这个问题的部分解决方案,但由于没有人找到完整的解决方案,我将 post 这个,也许会有帮助。
如果您覆盖 UINavigationBar
的 hitTest
方法,您可以通过按住 UINavigationBar
:
拖动模式来解决此问题
extension UINavigationBar {
override public func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
guard let view = super.hitTest(point, withEvent: event) else { return nil }
if view.isKindOfClass(UIControl) {
return super.hitTest(point, withEvent: event)
} else {
return nil
}
}
}
不幸的是,如果您在 UINavigationBar
上按住 UIBarButtonItem
拖动模态框,故障仍然存在。
您也可以尝试另一种方法。
如您所见,pan.translationInView(view)
returns 不正确的值导致动画跳转。
在拖动过程中,您需要将此值与模态视图的 y
坐标进行比较。您可以通过检查模态视图控制器的表示层来获取此值:
...
let translation = pan.translationInView(view)
if let layer = view.layer.presentationLayer() {
print(layer.frame.origin.y)
}
...
你可以看到当pan.translationInView(view)
开始显示错误值时,layer.frame.origin.y
在那一刻仍然是正确的。您可以比较这两个值并在值不正确时找到模式,并通过向 translation.y
值添加几个点来更改它以更正。
在通过 UIPercentDrivenInteractiveTransition
实现模态视图控制器的交互式关闭(向下拖动模态应该关闭它)时,我们已经 运行 解决了这个问题。
设置:
- 设置
UIViewController
嵌入UINavigationController
至少有一个按钮UINavigationBar
- 模态呈现
UINavigationController
中嵌入的另一个UIViewController
,至少有一个UINavigationBar
中的按钮
- 设置
UIPanGestureRecognizer
模态呈现UINavigationController
以驱动UIPercentDrivenInteractiveTransition
- 将模态向下拖动 "holding" 按
UINavigationBar
上的点
问题:
缓慢向下拖动时,动画故障导致模态视图上下跳动
仅在 :
时出现故障- 两个
UINavigationBar
都至少有一个按钮 - 你"hold"模态被点上
UINavigationBar
- 两个
可以从 github repo 下载最小示例。
有人遇到过这样的问题吗?有什么解决方法吗?我们的设置有什么缺陷吗?
更新
问题已在 运行 上面的 iPhone 5 模拟器上用 iOS 9.3
、OSX 10.11.4
、Xcode [=26= 编译的项目进行了模拟].
更新 2
进一步调查表明,该问题可能不在动画中:出于某种原因,在给定设置中 pan.translationInView(view)
返回意外值,导致动画跳转。
部分解决方法
根据 Vladimir 的想法,我们通过覆盖 UINavigationBar
的 hitTest
方法部分解决了这个问题:
class DraggableNavigationBar: UINavigationBar {
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
guard let view = super.hitTest(point, withEvent: event) else { return nil }
if view is UIControl || pointIsInsideNavigationButton(point) {
return view
} else {
return nil
}
}
private func pointIsInsideNavigationButton(point: CGPoint) -> Bool {
return subviews
.filter { [=10=].frame.contains(point) }
.filter { String([=10=].dynamicType) == "UINavigationItemButtonView" }
.isEmpty == false
}
}
我没有完整的解决方案,但我能够将故障减少一定程度。我可以在 iPhone 5 秒内使用 iOS 9.3.2
[通过按住导航栏向下拖动屏幕]
问题似乎出在 DismissalAnimator
的 UIView.animateWithDuration
块中。通过注释掉延迟和选项,即将它们保持为默认值,您可以减少视图的跳跃。您也可以尝试检查获得最小跳跃的不同 UIViewAnimationOptions
。
UIView.animateWithDuration(0.3,
animations: {
dismissedView.frame = finalFrame
},
completion: { _ in
let didComplete = !transitionContext.transitionWasCancelled()
transitionContext.completeTransition(didComplete)
}
)
a question 似乎正在处理您面临的相同问题。并且响应从禁用自动布局,将 layoutIfNeeded
放入动画块 [尝试过,都没有用]。
非常有趣的故障。几天前我找到了这个问题的部分解决方案,但由于没有人找到完整的解决方案,我将 post 这个,也许会有帮助。
如果您覆盖 UINavigationBar
的 hitTest
方法,您可以通过按住 UINavigationBar
:
extension UINavigationBar {
override public func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
guard let view = super.hitTest(point, withEvent: event) else { return nil }
if view.isKindOfClass(UIControl) {
return super.hitTest(point, withEvent: event)
} else {
return nil
}
}
}
不幸的是,如果您在 UINavigationBar
上按住 UIBarButtonItem
拖动模态框,故障仍然存在。
您也可以尝试另一种方法。
如您所见,pan.translationInView(view)
returns 不正确的值导致动画跳转。
在拖动过程中,您需要将此值与模态视图的 y
坐标进行比较。您可以通过检查模态视图控制器的表示层来获取此值:
...
let translation = pan.translationInView(view)
if let layer = view.layer.presentationLayer() {
print(layer.frame.origin.y)
}
...
你可以看到当pan.translationInView(view)
开始显示错误值时,layer.frame.origin.y
在那一刻仍然是正确的。您可以比较这两个值并在值不正确时找到模式,并通过向 translation.y
值添加几个点来更改它以更正。