อัปเดตสำหรับ iOS 13.4
iOS 13.4 ทำลายโซลูชันก่อนหน้าดังนั้นสิ่งต่างๆจะน่าเกลียด ดูเหมือนว่าใน iOS 13.4 พฤติกรรมนี้จะถูกควบคุมโดยวิธีส่วนตัว_gestureRecognizer:shouldReceiveEvent:
(เพื่อไม่ให้สับสนกับshouldReceive
วิธีสาธารณะใหม่ที่เพิ่มใน iOS 13.4)
ฉันพบว่าโซลูชันอื่น ๆ ที่โพสต์แทนที่ผู้รับมอบสิทธิ์หรือการตั้งค่าเป็นศูนย์ทำให้เกิดพฤติกรรมที่ไม่คาดคิด
ในกรณีของฉันเมื่อฉันอยู่ที่ด้านบนสุดของสแต็กการนำทางและพยายามใช้ท่าทางเพื่อแสดงขึ้นอีกครั้งมันจะล้มเหลว (ตามที่คาดไว้) แต่ความพยายามที่จะผลักดันไปยังสแต็กในภายหลังจะเริ่มทำให้เกิดความผิดพลาดแบบกราฟิกแปลก ๆ ใน แถบนำทาง. สิ่งนี้สมเหตุสมผลเนื่องจากมีการใช้ผู้รับมอบสิทธิ์ในการจัดการมากกว่าว่าจะบล็อกท่าทางไม่ให้รับรู้เมื่อแถบนำทางถูกซ่อนอยู่หรือไม่และพฤติกรรมอื่น ๆ ทั้งหมดนั้นก็ถูกโยนทิ้งไป
จากการทดสอบของฉันก็ปรากฏว่าเป็นวิธีการที่ผู้แทนจากเดิมคือการใช้เพื่อป้องกันท่าทางจากการรับรู้เมื่อแถบนำทางถูกซ่อนไว้ไม่ได้gestureRecognizer(_:, shouldReceiveTouch:)
gestureRecognizerShouldBegin(_:)
โซลูชันอื่น ๆ ที่ใช้gestureRecognizerShouldBegin(_:)
ในงานที่ได้รับมอบหมายเนื่องจากการขาดการนำไปใช้gestureRecognizer(_:, shouldReceiveTouch:)
จะทำให้พฤติกรรมเริ่มต้นของการรับสัมผัสทั้งหมด
โซลูชันของ @Nathan Perry ใกล้เข้ามาแล้ว แต่หากไม่มีการใช้งานrespondsToSelector(_:)
รหัส UIKit ที่ส่งข้อความไปยังผู้รับมอบสิทธิ์จะเชื่อว่าไม่มีการใช้งานสำหรับวิธีการมอบหมายอื่นใดและforwardingTargetForSelector(_:)
จะไม่ถูกเรียก
ดังนั้นเราจึงควบคุมท่าทางสัมผัส (_:, shouldReceiveTouch :) ในสถานการณ์เฉพาะที่เราต้องการปรับเปลี่ยนพฤติกรรมและส่งต่อทุกอย่างไปยังผู้รับมอบสิทธิ์
class AlwaysPoppableNavigationController : UINavigationController {
private var alwaysPoppableDelegate: AlwaysPoppableDelegate!
override func viewDidLoad() {
super.viewDidLoad()
self.alwaysPoppableDelegate = AlwaysPoppableDelegate(navigationController: self, originalDelegate: self.interactivePopGestureRecognizer!.delegate!)
self.interactivePopGestureRecognizer!.delegate = self.alwaysPoppableDelegate
}
}
private class AlwaysPoppableDelegate : NSObject, UIGestureRecognizerDelegate {
weak var navigationController: AlwaysPoppableNavigationController?
weak var originalDelegate: UIGestureRecognizerDelegate?
init(navigationController: AlwaysPoppableNavigationController, originalDelegate: UIGestureRecognizerDelegate) {
self.navigationController = navigationController
self.originalDelegate = originalDelegate
}
@objc func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if let navigationController = navigationController, navigationController.isNavigationBarHidden && navigationController.viewControllers.count > 1 {
return true
}
else if let originalDelegate = originalDelegate {
return originalDelegate.gestureRecognizer!(gestureRecognizer, shouldReceive: touch)
}
else {
return false
}
}
@objc func _gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceiveEvent event: UIEvent) -> Bool {
if let navigationController = navigationController, navigationController.isNavigationBarHidden && navigationController.viewControllers.count > 1 {
return true
}
else if let originalDelegate = originalDelegate {
let selector = #selector(_gestureRecognizer(_:shouldReceiveEvent:))
if originalDelegate.responds(to: selector) {
let result = originalDelegate.perform(selector, with: gestureRecognizer, with: event)
return result != nil
}
}
return false
}
override func responds(to aSelector: Selector) -> Bool {
if #available(iOS 13.4, *) {
return originalDelegate?.responds(to: aSelector) ?? false
}
else {
if aSelector == #selector(gestureRecognizer(_:shouldReceive:)) {
return true
}
else {
return originalDelegate?.responds(to: aSelector) ?? false
}
}
}
override func forwardingTarget(for aSelector: Selector) -> Any? {
if #available(iOS 13.4, *), aSelector == #selector(_gestureRecognizer(_:shouldReceiveEvent:)) {
return nil
}
else {
return self.originalDelegate
}
}
}