We have run into this issue when implementing interactive dismissal of a modal view controller (dragging modal down should dismiss it) via UIPercentDrivenInteractiveTransition
.
Setup:
UIViewController
embedded in UINavigationController
with at least one button in UINavigationBar
UIViewController
embedded in UINavigationController
with at least one button in UINavigationBar
UIPanGestureRecognizer
on modaly presented UINavigationController
to drive UIPercentDrivenInteractiveTransition
UINavigationBar
Issue:
while slowly dragging down, animation glitches causing modal view to jump up and down
glitch only appears when :
UINavigationBar
s have at least one button on themUINavigationBar
Minimal example can be downloaded from github repo.
Has anyone come accross such an issue? Are there any workarounds? Is there some flaw in our setup?
Update
Issue has been simulated on running project above on iPhone 5 simulator with iOS 9.3
, OSX 10.11.4
, compiled with Xcode 7.3.1
.
Update 2
Further investigation showed, that issue is probably not in the animation: For some reason in given setup pan.translationInView(view)
is returning unexpected values which causes animation to jump.
Partial workaround
Based on Vladimir's idea we partially fixed the issue by overriding hitTest
method of UINavigationBar
:
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 { $0.frame.contains(point) }
.filter { String($0.dynamicType) == "UINavigationItemButtonView" }
.isEmpty == false
}
}
Very interesting glitch. I found a partial solution of this problem few days ago, and since nobody found a full solution, I'll post this, maybe it will be helpful.
If you override hitTest
method of UINavigationBar
you can get rid of this issue when you dragging modal by holding on 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
}
}
}
Unfortunately if you drag modal by holding on UIBarButtonItem
on UINavigationBar
, glitch still be present.
You can also try another approach.
As you noticed, pan.translationInView(view)
returns incorrect values which causes animation to jump.
You need to compare this value to y
coordinate of modal view during dragging. You can get this value by checking presentation layer of the modal view controller:
...
let translation = pan.translationInView(view)
if let layer = view.layer.presentationLayer() {
print(layer.frame.origin.y)
}
...
You can see that when pan.translationInView(view)
starts to show wrong value, layer.frame.origin.y
still will be correct in that moment. You can compare these two values and find the pattern when value is incorrect, and change it to correct by adding few points to translation.y
value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With