ไม่ปัดกลับเมื่อซ่อนแถบนำทางใน UINavigationController


86

ฉันชอบชุดรูดที่สืบทอดมาจากการฝังมุมมองของคุณในไฟล์UINavigationController. แต่น่าเสียดายที่ฉันไม่สามารถดูเหมือนจะหาทางที่จะซ่อนได้แต่ยังคงมีการติดต่อกลับกระทะรูดNavigationBar gestureฉันสามารถเขียนท่าทางสัมผัสที่กำหนดเองได้ แต่ฉันไม่ต้องการและใช้การUINavigationControllerปัดไปด้านหลังgestureแทน

ถ้าฉันยกเลิกการเลือกในกระดานเรื่องราวการปัดไปด้านหลังจะไม่ทำงาน

ป้อนคำอธิบายภาพที่นี่

หรือถ้าฉันซ่อนมันโดยทางโปรแกรมสถานการณ์เดียวกัน

ไม่มีวิธีซ่อนด้านบนNavigationBarและยังมีรูด?


1
การเพิ่ม UIGestureRecognizer เป็นที่ยอมรับหรือไม่ เป็นเรื่องง่ายที่จะดำเนินการ
SwiftArchitect

1
@ LancelotdelaMare ฉันพยายามหลีกเลี่ยงสิ่งนั้นเนื่องจากมันจะไม่ทำงานอย่างราบรื่นเหมือนการปัดกลับของ UINavigationController ฉันกำลังดู UIScreenEdgePanGestureRecognizer เนื่องจากบางคนบอกว่าช่วยได้ แต่ยังไม่ได้ใช้งาน กำลังมองหาโซลูชันที่เรียบง่ายและหรูหราที่สุดที่นี่
mihai

คำตอบ:


98

สับที่ทำงานคือการตั้งค่าinteractivePopGestureRecognizerผู้ร่วมประชุม 's ของUINavigationControllerการnilเช่นนี้

[self.navigationController.interactivePopGestureRecognizer setDelegate:nil];

แต่ในบางสถานการณ์อาจสร้างเอฟเฟกต์แปลก ๆ


16
"การปัดไปมาซ้ำ ๆ อาจทำให้จดจำท่าทางได้เมื่อมีตัวควบคุมมุมมองเพียงตัวเดียวบนสแต็กซึ่งจะทำให้ UI อยู่ในสถานะ (ที่วิศวกร UIKit ไม่คาดคิด) ซึ่งจะหยุดจดจำท่าทางใด ๆ "
HorseT

4
ทางเลือกที่อาจป้องกันของรัฐที่ไม่คาดคิดว่าจะมีการตั้งค่าให้วัตถุบางระดับต่ำ (ผมใช้ผู้รับมอบสิทธิ์ app ของฉัน) และดำเนินการgestureRecognizerShouldBeginกลับtrueถ้าnavigationController's viewControllerนับมีมากกว่า 0
เคนนี Winker

4
แม้ว่าจะได้ผล แต่ฉันขอแนะนำให้ทำเช่นนี้ การทำลายผู้รับมอบสิทธิ์ทำให้บล็อกเธรดหลักหายากและยากที่จะระบุ ปรากฎว่าไม่ใช่บล็อกเธรดหลัก แต่เป็นสิ่งที่ @HorseT อธิบายไว้
Josh Bernfeld

3
แอปของฉันบันทึกที่จับผู้รับมอบสิทธิ์จากนั้นเรียกคืนเข้ามาviewWillDisappearและจนถึงขณะนี้ยังไม่พบผลข้างเคียง
Don Park

1
!!!! ไม่แนะนำอย่างยิ่งที่จะใช้วิธีนี้เมื่อใช้การปัดซ้ำ ๆ พฤติกรรมแปลก ๆ เกิดขึ้นด้านหลังถูกปิดใช้งานและแอพทั้งหมดไม่ตอบสนองอีกต่อไป
KarimIhab

81

ปัญหาเกี่ยวกับวิธีการอื่น ๆ

การตั้งค่าinteractivePopGestureRecognizer.delegate = nilมีผลข้างเคียงโดยไม่ได้ตั้งใจ

การตั้งค่าnavigationController?.navigationBar.hidden = trueใช้งานได้ แต่ไม่อนุญาตให้ซ่อนการเปลี่ยนแปลงในแถบนำทาง

ประการสุดท้ายโดยทั่วไปแล้วการสร้างวัตถุแบบจำลองที่เหมาะUIGestureRecognizerDelegateสำหรับตัวควบคุมการนำทางของคุณเป็นวิธีปฏิบัติที่ดีกว่า การตั้งค่าเป็นคอนโทรลเลอร์ในUINavigationControllerสแตกคือสิ่งที่ทำให้เกิดEXC_BAD_ACCESSข้อผิดพลาด

โซลูชั่นเต็มรูปแบบ

ขั้นแรกเพิ่มชั้นเรียนนี้ในโครงการของคุณ:

class InteractivePopRecognizer: NSObject, UIGestureRecognizerDelegate {

    var navigationController: UINavigationController

    init(controller: UINavigationController) {
        self.navigationController = controller
    }

    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return navigationController.viewControllers.count > 1
    }

    // This is necessary because without it, subviews of your top controller can
    // cancel out your gesture recognizer on the edge.
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

จากนั้นตั้งค่าตัวควบคุมการนำทางของคุณinteractivePopGestureRecognizer.delegateเป็นอินสแตนซ์ของInteractivePopRecognizerคลาสใหม่ของคุณ

var popRecognizer: InteractivePopRecognizer?

override func viewDidLoad() {
    super.viewDidLoad()
    setInteractiveRecognizer()
}

private func setInteractiveRecognizer() {
    guard let controller = navigationController else { return }
    popRecognizer = InteractivePopRecognizer(controller: controller)
    controller.interactivePopGestureRecognizer?.delegate = popRecognizer
}

เพลิดเพลินไปกับแถบนำทางที่ซ่อนอยู่โดยไม่มีผลข้างเคียงซึ่งใช้งานได้แม้ว่าตัวควบคุมด้านบนของคุณจะมีมุมมองย่อยแบบตารางคอลเลกชันหรือแบบเลื่อน


2
ทางออกที่ดี!
Matt Butler

2
คำตอบที่ดีที่สุดขอบคุณ!
Dory Daniel

3
@HunterMaximillionMonk ขอบคุณสำหรับโซลูชันที่ยอดเยี่ยม ใช้งานได้เหมือนมีเสน่ห์

2
ตอบโจทย์ที่สุดแน่นอน!
daxh

2
ทำงานบน iOS 13.5, 12.4.6 และ 10.3.4 ขอบคุณ.
ДенисПопов

55

ในกรณีของฉันเพื่อป้องกันผลกระทบแปลก ๆ

ตัวควบคุมมุมมองรูท

override func viewDidLoad() {
    super.viewDidLoad()

    // Enable swipe back when no navigation bar
    navigationController?.interactivePopGestureRecognizer?.delegate = self
}

// UIGestureRecognizerDelegate
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if let navVc = navigationController {
      return navVc.viewControllers.count > 1
    }
    return false
}

2
บางครั้งฉันได้รับ EXC_BAD_ACCESS เมื่อใช้สิ่งนี้
Andrey Gordeev

สำหรับฉันมันไม่ได้ทำให้ท่าทางใช้งานได้และมักจะขัดข้องด้วยEXEC_BAD_ACCESS
Benjohn

2
อย่าลืมเพิ่มUIGestureRecognizerDelegateไปยังตัวควบคุมมุมมองรูท ... ในกรณีของฉันผู้ร่วมประชุมถูกตั้งค่าเป็นศูนย์ในตัวควบคุมมุมมองที่ใหม่กว่าตัวควบคุมมุมมองรูทดังนั้นเมื่อกลับไปที่ตัวควบคุมมุมมองรูทgestureRecognizerShouldBeginจะไม่ถูกเรียก ดังนั้นผมจึงวางใน.delegate = self viewDidAppear()ที่แก้ไขเอฟเฟกต์แปลก ๆ ในเคสของฉัน .. ไชโย!
Wiingaard

@AndreyGordeev คุณช่วยให้รายละเอียดเกี่ยวกับเวลาที่EXEC_BAD_ACCESSเกิดขึ้นได้ไหม?
Jaybo

ข้อมูลเพิ่มเติมเกี่ยวกับEXC_BAD_ACCESSข้อผิดพลาด: stackoverflow.com/questions/28746123/…
Andrey Gordeev

25

อัปเดตสำหรับ 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
    }

    // For handling iOS before 13.4
    @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
        }
    }

    // For handling iOS 13.4+
    @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, *) {
            // iOS 13.4+ does not need to override responds(to:) behavior, it only uses forwardingTarget
            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
        }
    }
}

1
ดูเหมือนว่าทางออกของคุณจะดีที่สุดสำหรับช่วงเวลานี้ ขอบคุณ!
Timur Bernikovich

"แต่ความพยายามในการผลักดันสแต็กในภายหลังจะทำให้กราฟิกผิดพลาดแปลก ๆ ในแถบนำทาง" - ฉันสับสนตรงนี้ ฉันคิดว่าเราไม่มีแถบนำทาง? นั่นคือคำถาม? ในสถานการณ์ของฉันฉันมีตัวควบคุมการนำทางที่ฝังอยู่ในตัวควบคุมมุมมองเด็กที่ไม่มีแถบนำทาง VC ที่มีอยู่มีตัวควบคุมการนำทาง ดังนั้นฉันจึงปล่อยให้ VC ที่มีอยู่เป็นผู้รับมอบสิทธิ์ของจดจำและทำgestureRecognizerShouldBegin:สิ่งนั้นและมันก็ "ดูเหมือนจะได้ผล" สงสัยว่าฉันควรมองหา
skagedal

2
สิ่งนี้มีการรั่วไหลของหน่วยความจำเนื่องจากnavigationControllerเป็นข้อมูลอ้างอิงที่ชัดเจนใน AlwaysPoppableDelegate ฉันได้แก้ไขโค้ดเพื่อให้เป็นweakข้อมูลอ้างอิง
Graham Perks

3
โซลูชันที่ดีนี้ใช้ไม่ได้อีกต่อไปใน iOS 13.4
Ely

@ChrisVasselli สุดยอดจริงๆขอบคุณ! หวังว่านี่จะผ่านการตรวจสอบวิธีการส่วนตัวของการตรวจสอบ App Store
เอไล

16

คุณสามารถ subclass UINavigationController ดังต่อไปนี้:

@interface CustomNavigationController : UINavigationController<UIGestureRecognizerDelegate>

@end

การนำไปใช้:

@implementation CustomNavigationController

- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated {
    [super setNavigationBarHidden:hidden animated:animated];
    self.interactivePopGestureRecognizer.delegate = self;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (self.viewControllers.count > 1) {
        return YES;
    }
    return NO;
}

@end

2
การใช้วิธีนี้เป็นการทำลายท่าทางป๊อปในการUIPageViewControllerเลื่อนหน้าจอ
atulkhatri

ฉันพบว่าจำเป็นต้องตรวจสอบ viewController.count> 1 หากผู้ใช้พยายามปัดกลับด้วย VC รูทเท่านั้น UI จะค้างในการพุช VC ถัดไป
VaporwareWolf

12

คำตอบง่ายๆไม่มีผลข้างเคียง

แม้ว่าคำตอบส่วนใหญ่ที่นี่จะดี แต่ก็ดูเหมือนว่าจะมีผลข้างเคียงที่ไม่ได้ตั้งใจ (แอปทำลาย) หรือเป็นรายละเอียด

วิธีแก้ปัญหาที่เรียบง่าย แต่ใช้งานได้ดีที่สุดที่ฉันสามารถทำได้มีดังต่อไปนี้:

ใน ViewController ที่คุณซ่อน navigationBar

class MyNoNavBarViewController: UIViewController {
    
    // needed for reference when leaving this view controller
    var initialInteractivePopGestureRecognizerDelegate: UIGestureRecognizerDelegate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // we will need a reference to the initial delegate so that when we push or pop.. 
        // ..this view controller we can appropriately assign back the original delegate
        initialInteractivePopGestureRecognizerDelegate = self.navigationController?.interactivePopGestureRecognizer?.delegate
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)

        // we must set the delegate to nil whether we are popping or pushing to..
        // ..this view controller, thus we set it in viewWillAppear()
        self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(true)

        // and every time we leave this view controller we must set the delegate back..
        // ..to what it was originally
        self.navigationController?.interactivePopGestureRecognizer?.delegate = initialInteractivePopGestureRecognizerDelegate
    }
}

คำตอบอื่น ๆ แนะนำเพียงการตั้งค่าผู้รับมอบสิทธิ์เป็นศูนย์ การปัดไปข้างหลังไปยังตัวควบคุมมุมมองเริ่มต้นบนสแต็กการนำทางจะทำให้ท่าทางทั้งหมดถูกปิดใช้งาน บางทีการกำกับดูแลบางอย่างของ UIKit / UIGesture devs

เช่นกันคำตอบบางส่วนที่ฉันได้นำไปใช้ในที่นี้ส่งผลให้เกิดพฤติกรรมการนำทางของ Apple ที่ไม่ได้มาตรฐาน (โดยเฉพาะทำให้สามารถเลื่อนขึ้นหรือลงได้ในขณะที่ปัดไปข้างหลังด้วย) คำตอบเหล่านี้ดูเหมือนจะละเอียดเกินไปและในบางกรณีก็ไม่สมบูรณ์


viewDidLoad()ไม่ใช่สถานที่ที่ดีในการจับภาพinitialInteractivePopGestureRecognizerDelegateเนื่องจากnavigationControllerอาจไม่มีศูนย์ (ยังไม่ถูกผลักลงในสแต็ก) viewWillAppearสถานที่ที่คุณซ่อนแถบนำทางจะเหมาะสมกว่า
nCod3d

10

จากคำตอบของHunter Maximillion Monkฉันได้สร้างคลาสย่อยสำหรับ UINavigationController จากนั้นตั้งค่าคลาสที่กำหนดเองสำหรับ UINavigationController ในสตอรี่บอร์ดของฉัน รหัสสุดท้ายของทั้งสองคลาสมีลักษณะดังนี้:

InteractivePopRecognizer:

class InteractivePopRecognizer: NSObject {

    // MARK: - Properties

    fileprivate weak var navigationController: UINavigationController?

    // MARK: - Init

    init(controller: UINavigationController) {
        self.navigationController = controller

        super.init()

        self.navigationController?.interactivePopGestureRecognizer?.delegate = self
    }
}

extension InteractivePopRecognizer: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return (navigationController?.viewControllers.count ?? 0) > 1
    }

    // This is necessary because without it, subviews of your top controller can cancel out your gesture recognizer on the edge.
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

HiddenNavBarNavigationController:

class HiddenNavBarNavigationController: UINavigationController {

    // MARK: - Properties

    private var popRecognizer: InteractivePopRecognizer?

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        setupPopRecognizer()
    }

    // MARK: - Setup

    private func setupPopRecognizer() {
        popRecognizer = InteractivePopRecognizer(controller: self)
    }
}

สตอรี่บอร์ด:

คลาสที่กำหนดเองของ Storyboard nav controller


8

ดูเหมือนวิธีแก้ปัญหาโดย @ChrisVasseli จะดีที่สุด ฉันต้องการให้โซลูชันเดียวกันใน Objective-C เนื่องจากคำถามเกี่ยวกับ Objective-C (ดูแท็ก)

@interface InteractivePopGestureDelegate : NSObject <UIGestureRecognizerDelegate>

@property (nonatomic, weak) UINavigationController *navigationController;
@property (nonatomic, weak) id<UIGestureRecognizerDelegate> originalDelegate;

@end

@implementation InteractivePopGestureDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if (self.navigationController.navigationBarHidden && self.navigationController.viewControllers.count > 1) {
        return YES;
    } else {
        return [self.originalDelegate gestureRecognizer:gestureRecognizer shouldReceiveTouch:touch];
    }
}

- (BOOL)respondsToSelector:(SEL)aSelector
{
    if (aSelector == @selector(gestureRecognizer:shouldReceiveTouch:)) {
        return YES;
    } else {
        return [self.originalDelegate respondsToSelector:aSelector];
    }
}

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    return self.originalDelegate;
}

@end

@interface NavigationController ()

@property (nonatomic) InteractivePopGestureDelegate *interactivePopGestureDelegate;

@end

@implementation NavigationController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.interactivePopGestureDelegate = [InteractivePopGestureDelegate new];
    self.interactivePopGestureDelegate.navigationController = self;
    self.interactivePopGestureDelegate.originalDelegate = self.interactivePopGestureRecognizer.delegate;
    self.interactivePopGestureRecognizer.delegate = self.interactivePopGestureDelegate;
}

@end

3
เพราะ ObjC ยังไม่ตาย! 😉
MonsieurDart

2
นี่คือวิธีแก้ปัญหาที่ถูกต้อง วิธีแก้ปัญหาอื่นใดที่ไม่ได้ส่งต่อไปยังผู้รับมอบสิทธิ์ดั้งเดิมนั้นไม่ถูกต้อง
Josh Bernfeld

6

ทางออกของฉันคือการขยายUINavigationControllerชั้นเรียนโดยตรง:

import UIKit

extension UINavigationController: UIGestureRecognizerDelegate {

    override open func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        self.interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return self.viewControllers.count > 1
    }

}

วิธีนี้ตัวควบคุมการนำทางทั้งหมดจะปิดได้โดยการเลื่อน


สิ่งนี้ผิดปกติมากพอที่ทำให้การviewDidAppearเรียก VC ทั้งหมดที่เป็นของตัวควบคุมการนำทางใด ๆ ถูกละเว้น
cumanzor

4

คุณสามารถทำได้โดยใช้ Proxy Delegate เมื่อคุณกำลังสร้างตัวควบคุมการนำทางให้คว้าผู้รับมอบสิทธิ์ที่มีอยู่ และส่งผ่านไปยังพร็อกซี จากนั้นส่งวิธีการมอบหมายทั้งหมดไปยังผู้รับมอบสิทธิ์ที่มีอยู่ยกเว้นการgestureRecognizer:shouldReceiveTouch:ใช้forwardingTargetForSelector:

ติดตั้ง:

let vc = UIViewController(nibName: nil, bundle: nil)
let navVC = UINavigationController(rootViewController: vc)
let bridgingDelegate = ProxyDelegate()
bridgingDelegate.existingDelegate = navVC.interactivePopGestureRecognizer?.delegate
navVC.interactivePopGestureRecognizer?.delegate = bridgingDelegate

ผู้รับมอบฉันทะ:

class ProxyDelegate: NSObject, UIGestureRecognizerDelegate {
    var existingDelegate: UIGestureRecognizerDelegate? = nil

    override func forwardingTargetForSelector(aSelector: Selector) -> AnyObject? {
        return existingDelegate
    }

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
        return true
    }  
}

คำตอบนี้คือสไตล์ Obj-C ที่แท้จริง!
Sound Blaster

forwardingTargetForSelector จะช่วยฉันประหยัดเวลาได้มากในโครงการที่ผ่านมาถ้าฉันรู้เกี่ยวกับมัน สิ่งที่ดี!
VaporwareWolf

4

คำตอบของ Hunter Monk นั้นยอดเยี่ยมมาก แต่น่าเสียดายที่ใน iOS 13.3.1 ใช้งานไม่ได้

ผมจะอธิบายวิธีการซ่อนอีกและไม่สูญเสียUINavigationBar swipe to back gestureฉันได้ทดสอบบน iOS 13.3.1 และ 12.4.3 แล้วและใช้งานได้

คุณต้องสร้างคลาสที่กำหนดเองUINavigationControllerและตั้งค่าคลาสนั้นสำหรับUINavigationControllerในStoryboard

ตั้งค่าคลาสที่กำหนดเองเป็น <code> UINavigationController </code>

อย่าซ่อนNavigationBarบนStoryboard

<code> UINavigationController </code> ตัวตรวจสอบคุณสมบัติ:

ตัวอย่างบนStoryboard:

สตอรี่บอร์ด:

และในที่สุดก็ใส่นี้: navigationBar.isHidden = trueในviewDidLoadของCustomNavigationControllerชั้น

ตรวจสอบให้แน่ใจอย่าใช้วิธีนี้ในการsetNavigationBarHidden(true, animated: true)ซ่อนไฟล์NavigationBar.

import UIKit

class CustomNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationBar.isHidden = true
    }
}

2
ฉันได้ทดสอบสิ่งนี้กับอุปกรณ์จริง iPhone 6S Plus ด้วยiOS 13.4.1และปัดไปมาได้
Emre Aydin

1

Xamarin คำตอบ:

ใช้IUIGestureRecognizerDelegateอินเทอร์เฟซในนิยามคลาสของ ViewController ของคุณ:

public partial class myViewController : UIViewController, IUIGestureRecognizerDelegate

ใน ViewController ของคุณเพิ่มวิธีการต่อไปนี้:

[Export("gestureRecognizerShouldBegin:")]
public bool ShouldBegin(UIGestureRecognizer recognizer) {
  if (recognizer is UIScreenEdgePanGestureRecognizer && 
      NavigationController.ViewControllers.Length == 1) {
    return false;
  }
  return true;
}

ใน ViewController ของคุณให้ViewDidLoad()เพิ่มบรรทัดต่อไปนี้:

NavigationController.InteractivePopGestureRecognizer.Delegate = this;

สันนิษฐานว่าสิ่งนี้อยู่ในUINavigationControllerตัวควบคุมมุมมองรูทของ? ฉันได้รับEXEC_BAD_ACCESSเมื่อฉันลองสิ่งนี้
Benjohn

คุณสามารถแพนขอบบนตัวควบคุมมุมมองรูทได้หรือไม่? ไม่น่าจะเป็นไปได้เพราะเมื่อคุณอยู่ที่ root VC คุณได้เปิด VCs อื่น ๆ ทั้งหมดและความยาวของอาร์เรย์ VC ของ Nav ของคุณควรเป็น 1
Ahmad

gestureRecognizerShouldBegin:ความผิดพลาดที่เกิดขึ้นก่อนที่จะเรียกร้องให้
Benjohn

1
คุณสามารถโพสต์รหัส VC ของคุณในคำถามใหม่หรือในฟอรัม Xamarin ได้หรือไม่?
Ahmad

ไม่ฉันไม่ได้ ฉันคิดว่าจะปล่อยให้. 1!
Benjohn

1

ฉันได้ลองใช้แล้วและทำงานได้อย่างสมบูรณ์: วิธีซ่อนแถบนำทางโดยไม่สูญเสียความสามารถในการสไลด์กลับ

แนวคิดคือการใช้ "UIGestureRecognizerDelegate" ใน. h ของคุณและเพิ่มสิ่งนี้ลงในไฟล์. m ของคุณ

- (void)viewWillAppear:(BOOL)animated {
// hide nav bar
[[self navigationController] setNavigationBarHidden:YES animated:YES];

// enable slide-back
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.enabled = YES;
    self.navigationController.interactivePopGestureRecognizer.delegate = self;
  }
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
   return YES;  
}

1

นี่คือวิธีแก้ปัญหาของฉัน: ฉันกำลังเปลี่ยนอัลฟ่าบนแถบนำทาง แต่ไม่ได้ซ่อนแถบนำทาง ตัวควบคุมมุมมองของฉันทั้งหมดเป็นคลาสย่อยของ BaseViewController ของฉันและที่นั่นฉันมี:

    override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    navigationController?.navigationBar.alpha = 0.0
}

คุณยังสามารถ subclass UINavigationController และวางเมธอดนั้นไว้ที่นั่น


0

บางคนประสบความสำเร็จโดยเรียกsetNavigationBarHiddenวิธีการนี้ด้วยภาพเคลื่อนไหวYESแทน


ฉันพยายามไม่มีโชค กำลังอัปเดตคำตอบของฉันเพื่อให้ครอบคลุมคำแนะนำนี้
mihai

0

ในตัวควบคุมมุมมองของฉันที่ไม่มีแถบนำทางฉันใช้

open override func viewWillAppear(_ animated: Bool) {
  super.viewWillAppear(animated)

  CATransaction.begin()
  UIView.animate(withDuration: 0.25, animations: { [weak self] in
    self?.navigationController?.navigationBar.alpha = 0.01
  })
  CATransaction.commit()
}

open override func viewWillDisappear(_ animated: Bool) {
  super.viewWillDisappear(animated)
  CATransaction.begin()
  UIView.animate(withDuration: 0.25, animations: { [weak self] in
    self?.navigationController?.navigationBar.alpha = 1.0
  })
  CATransaction.commit()
}

ในระหว่างการปิดการทำงานแบบโต้ตอบปุ่มย้อนกลับจะส่องผ่านซึ่งเป็นสาเหตุที่ฉันซ่อนมัน


-2

มีวิธีง่ายๆที่ฉันพยายามและใช้งานได้อย่างสมบูรณ์นี่คือใน Xamarin.iOS แต่สามารถใช้กับเนทีฟได้เช่นกัน:

    public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);
        this.NavigationController.SetNavigationBarHidden(true, true);
    }

    public override void ViewDidAppear(bool animated)
    {
        base.ViewDidAppear(animated);
        this.NavigationController.SetNavigationBarHidden(false, false);
        this.NavigationController.NavigationBar.Hidden = true;
    }

    public override void ViewWillDisappear(bool animated)
    {
        base.ViewWillDisappear(animated);
        this.NavigationController.SetNavigationBarHidden(true, false);
    }

-6

ต่อไปนี้เป็นวิธีปิดใช้งานตัวจดจำท่าทางเมื่อผู้ใช้เลื่อนออกจาก ViewController คุณสามารถวางลงใน viewWillAppear () หรือบนเมธอด ViewDidLoad () ของคุณได้

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}

โปรดอ่านคำถามก่อนโพสต์คำตอบ คำถามเกี่ยวกับการเปิดใช้งานไม่ใช่การปิดใช้งาน เรารักท่าทางป๊อป
Yogesh Maheshwari
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.