Không vuốt lại khi ẩn Thanh điều hướng trong UINavigationController


86

Tôi thích gói vuốt được kế thừa từ việc nhúng các chế độ xem của bạn vào a UINavigationController. Thật không may, tôi dường như không thể tìm ra cách để ẩn NavigationBarnhưng vẫn có thao tác vuốt ngược lại gesture. Tôi có thể viết các cử chỉ tùy chỉnh nhưng tôi không thích và thay vào đó tôi dựa vào UINavigationControllerthao tác vuốt ngược gesture.

nếu tôi bỏ chọn nó trong bảng phân cảnh, thao tác vuốt ngược lại không hoạt động

nhập mô tả hình ảnh ở đây

cách khác nếu tôi ẩn nó theo chương trình, cùng một kịch bản.

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.navigationController setNavigationBarHidden:YES animated:NO]; // and animated:YES
}

Không có cách nào để ẩn đầu NavigationBarmà vẫn có thao tác vuốt?


1
Việc thêm UIGestureRecognizer có được chấp nhận không? Thật dễ dàng để thực hiện.
SwiftArchitect

1
@LancelotdelaMare, tôi đã cố gắng tránh điều đó vì nó sẽ không hoạt động trơn tru như vuốt ngược UINavigationController. Tôi đang xem xét UIScreenEdgePanGestureRecognizer vì một số người nói rằng nó hữu ích nhưng vẫn chưa làm được. Tìm kiếm giải pháp đơn giản và thanh lịch nhất ở đây.
mihai

Câu trả lời:


96

Một cuộc tấn công đang hoạt động là đặt người interactivePopGestureRecognizerđại diện của cái UINavigationControllerthành nilnhư thế này:

[self.navigationController.interactivePopGestureRecognizer setDelegate:nil];

Nhưng trong một số tình huống, nó có thể tạo ra những hiệu ứng kỳ lạ.


16
"vuốt ngược lại nhiều lần có thể khiến cử chỉ được nhận dạng khi chỉ có một bộ điều khiển chế độ xem trên ngăn xếp, điều này sẽ đặt giao diện người dùng ở trạng thái (tôi nghĩ là không mong đợi bởi các kỹ sư UIKit) nơi nó ngừng nhận dạng bất kỳ cử chỉ nào"
HorseT

4
Một thay thế có thể bảo vệ chống lại trạng thái bất ngờ sẽ phải đặt nó vào một số đối tượng ở mức độ thấp (Tôi đã từng đại biểu ứng dụng của tôi) và thực hiện gestureRecognizerShouldBegin, trở về truenếu navigationController's viewControllercount là lớn hơn 0.
Kenny Winker

4
Mặc dù điều này hiệu quả, tôi thực sự khuyên bạn không nên làm điều này. Việc phá vỡ đại biểu gây ra một khối luồng chính hiếm gặp và khó xác định. Hóa ra nó không phải là một khối chủ đề chính mà là những gì @HorseT đã mô tả.
Josh Bernfeld

3
Ứng dụng của tôi lưu điều khiển đại biểu sau đó khôi phục nó viewWillDisappearvà cho đến nay vẫn chưa gặp phải tác dụng phụ bất lợi nào.
Don Park

1
!!!! Rất không khuyến khích sử dụng giải pháp này, khi liên tục sử dụng vuốt, một hành vi lạ xảy ra, mặt sau bị vô hiệu hóa và toàn bộ ứng dụng không phản hồi nữa
KarimIhab

79

Sự cố với các phương pháp khác

Cài đặt interactivePopGestureRecognizer.delegate = nilcó tác dụng phụ ngoài ý muốn.

Cài đặt navigationController?.navigationBar.hidden = truehoạt động, nhưng không cho phép ẩn thay đổi của bạn trong thanh điều hướng.

Cuối cùng, thông thường tốt hơn là tạo một đối tượng mô hình UIGestureRecognizerDelegatedành cho bộ điều khiển điều hướng của bạn. Đặt nó thành bộ điều khiển trong UINavigationControllerngăn xếp là nguyên nhân gây ra EXC_BAD_ACCESSlỗi.

Giải pháp đầy đủ

Đầu tiên, thêm lớp này vào dự án của bạn:

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
    }
}

Sau đó, đặt bộ điều khiển điều hướng của bạn interactivePopGestureRecognizer.delegatethành một phiên bản của InteractivePopRecognizerlớp mới của bạn .

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
}

Tận hưởng thanh điều hướng ẩn mà không có tác dụng phụ, hoạt động ngay cả khi bộ điều khiển hàng đầu của bạn có bảng, bộ sưu tập hoặc chế độ xem cuộn.


1
Giải pháp tuyệt vời!
Matt Butler

1
Câu trả lời tốt nhất, Cảm ơn!
Dory Daniel

2
@HunterMaximillionMonk cảm ơn vì giải pháp tuyệt vời. Nó hoạt động như một nét duyên dáng
như diu

1
@HunterMaximillionMonk điều này có vẻ hoạt động chính xác nhưng vấn đề với nó khi tôi có nhiều bộ điều khiển thì sau một thời gian bật lên, nó sẽ ngừng hoạt động.
Premal Khetani

1
Chắc chắn câu trả lời tốt nhất!
daxh

54

Trong trường hợp của tôi, để ngăn chặn các hiệu ứng lạ

Bộ điều khiển chế độ xem gốc

override func viewDidLoad() {
    super.viewDidLoad()

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

}


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

http://www.gampood.com/pop-viewcontroller-with-out-navigation-bar/


2
Đôi khi tôi nhận được khi sử dụng EXC_BAD_ACCESS này
Andrey Gordeev

Đối với tôi, nó không làm cho công tác cử chỉ và thường xuyên bị treo vớiEXEC_BAD_ACCESS
Benjohn

2
Hãy nhớ thêm UIGestureRecognizerDelegatevào bộ điều khiển chế độ xem gốc ... Trong trường hợp của tôi, ủy quyền đã được đặt thành nil trong bộ điều khiển chế độ xem mới hơn bộ điều khiển chế độ xem gốc, vì vậy khi trả về bộ điều khiển chế độ xem gốc, gestureRecognizerShouldBeginnó không được gọi. Vì vậy, tôi đã đặt .delegate = selfvào viewDidAppear(). Điều đó đã giải quyết các hiệu ứng kỳ lạ trong trường hợp của tôi .. Cheers!
Wiingaard

@AndreyGordeev Bạn có thể vui lòng cho biết một số chi tiết về thời điểm EXEC_BAD_ACCESSxảy ra không?
Jaybo

Dưới đây là thông tin thêm về EXC_BAD_ACCESSlỗi: stackoverflow.com/questions/28746123/...
Andrey Gordeev

25

Cập nhật cho iOS 13.4

iOS 13.4 đã phá vỡ giải pháp trước đó, vì vậy mọi thứ sẽ trở nên tồi tệ. Có vẻ như trong iOS 13.4, hành vi này hiện được kiểm soát bởi một phương thức riêng tư _gestureRecognizer:shouldReceiveEvent:(đừng nhầm lẫn với shouldReceivephương thức công khai mới được thêm vào iOS 13.4).


Tôi nhận thấy rằng các giải pháp đã đăng khác ghi đè đại biểu hoặc đặt nó thành nil gây ra một số hành vi không mong muốn.

Trong trường hợp của tôi, khi tôi ở trên cùng của ngăn xếp điều hướng và cố gắng sử dụng cử chỉ để bật thêm một lần nữa, nó sẽ không thành công (như mong đợi), nhưng những nỗ lực tiếp theo để đẩy lên ngăn xếp sẽ bắt đầu gây ra lỗi đồ họa kỳ lạ trong thanh điều hướng. Điều này có ý nghĩa, bởi vì đại biểu đang được sử dụng để xử lý nhiều thứ hơn là chỉ chặn nhận dạng cử chỉ hay không khi thanh điều hướng bị ẩn và tất cả các hành vi khác đã bị loại bỏ.

Từ thử nghiệm của tôi, có vẻ như đó gestureRecognizer(_:, shouldReceiveTouch:)là phương pháp mà đại biểu ban đầu đang triển khai để chặn nhận dạng cử chỉ khi thanh điều hướng bị ẩn, chứ không phải gestureRecognizerShouldBegin(_:). Các giải pháp khác có thể thực hiện gestureRecognizerShouldBegin(_:)trong công việc ủy ​​quyền của họ vì thiếu việc triển khaigestureRecognizer(_:, shouldReceiveTouch:) sẽ gây ra hành vi mặc định là nhận tất cả các liên lạc.

Giải pháp của @Nathan Perry đã gần đạt được, nhưng không có triển khai respondsToSelector(_:), mã UIKit gửi thông báo đến người được ủy quyền sẽ tin rằng không có triển khai nào cho bất kỳ phương thức ủy quyền nào khác vàforwardingTargetForSelector(_:) sẽ không bao giờ được gọi.

Vì vậy, chúng tôi nắm quyền kiểm soát `scrollRecognizer (_ :, shouldReceiveTouch :) trong một kịch bản cụ thể mà chúng tôi muốn sửa đổi hành vi và chuyển tiếp mọi thứ khác tới đại biểu.

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
Có vẻ như giải pháp của bạn là tốt nhất cho thời điểm này. Cảm ơn!
Timur Bernikovich

"nhưng những nỗ lực tiếp theo để đẩy lên ngăn xếp sẽ bắt đầu gây ra lỗi đồ họa kỳ lạ trong thanh điều hướng" - Tôi bối rối ở đây. Tôi nghĩ rằng chúng tôi không có thanh điều hướng? Đó là câu hỏi? Trong tình huống của tôi, tôi có một bộ điều khiển điều hướng được nhúng làm bộ điều khiển chế độ xem trẻ em không có thanh điều hướng; VC chứa có các điều khiển điều hướng. Vì vậy, tôi đã để VC có chứa là đại biểu của trình nhận dạng và chỉ làm gestureRecognizerShouldBegin:điều đó, và nó "có vẻ hoạt động". Tự hỏi tôi có nên tìm kiếm.
skagedal

2
Điều này đã bị rò rỉ bộ nhớ vì navigationControllertham chiếu mạnh mẽ trong AlwaysPoppableDelegate. Tôi đã chỉnh sửa mã để làm cho nó trở thành một weaktài liệu tham khảo.
Graham Perks

3
Giải pháp tốt đẹp này không hoạt động nữa trong iOS 13.4
Ely

@ChrisVasselli Thực sự tuyệt vời, cảm ơn bạn! Hy vọng rằng điều này sẽ vượt qua kiểm tra phương pháp riêng tư của đánh giá App Store.
Ely

16

Bạn có thể phân lớp UINavigationController như sau:

@interface CustomNavigationController : UINavigationController<UIGestureRecognizerDelegate>

@end

Thực hiện:

@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
Sử dụng phương pháp này đang phá vỡ cử chỉ bật lên trong UIPageViewControllercuộn quá mức.
atulkhatri

Tôi thấy rằng cần kiểm tra viewController.count> 1. Nếu người dùng cố gắng vuốt lại chỉ với VC gốc, giao diện người dùng sẽ bị treo trong lần đẩy VC tiếp theo.
VaporwareWolf

11

Câu trả lời đơn giản, không có tác dụng phụ

Mặc dù hầu hết các câu trả lời ở đây là tốt, nhưng chúng dường như có tác dụng phụ không mong muốn (phá vỡ ứng dụng) hoặc dài dòng.

Giải pháp đơn giản nhưng đầy đủ chức năng nhất mà tôi có thể đưa ra là:

Trong ViewController mà bạn đang ẩn Thanh điều hướng,

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
    }
}

Các câu trả lời khác đã gợi ý chỉ đặt đại biểu thành nil. Vuốt ngược trở lại bộ điều khiển chế độ xem ban đầu trên ngăn xếp điều hướng dẫn đến việc tắt tất cả các cử chỉ. Có lẽ, một số kiểu giám sát của các nhà phát triển UIKit / UIGesture.

Ngoài ra, một số câu trả lời ở đây mà tôi đã triển khai dẫn đến hành vi điều hướng táo không chuẩn (cụ thể là cho phép khả năng cuộn lên hoặc xuống trong khi cũng có thể vuốt ngược). Những câu trả lời này cũng có vẻ hơi dài dòng và trong một số trường hợp không đầy đủ.


viewDidLoad()không phải là một nơi tốt để chụp initialInteractivePopGestureRecognizerDelegatenavigationControllercó thể không có ở đó (chưa được đẩy lên ngăn xếp). viewWillAppearnơi bạn đang ẩn thanh điều hướng sẽ thích hợp hơn
nCod3d

10

Dựa trên câu trả lời của Hunter Maximillion Monk , tôi đã tạo một lớp con cho UINavigationController và sau đó đặt lớp tùy chỉnh cho UINavigationController trong bảng phân cảnh của mình. Mã cuối cùng cho hai lớp trông như thế này:

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)
    }
}

Bảng phân cảnh:

Lớp tùy chỉnh điều khiển điều hướng bảng phân cảnh


8

Có vẻ như giải pháp do @ChrisVasseli cung cấp là tốt nhất. Tôi muốn cung cấp giải pháp tương tự trong Objective-C vì câu hỏi là về Objective-C (xem thẻ)

@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
Bởi vì ObjC vẫn chưa chết! 😉
MonsieurDart

2
Đây là giải pháp chính xác. Bất kỳ giải pháp nào khác không chuyển tiếp đến đại biểu ban đầu là không chính xác.
Josh Bernfeld

6

Giải pháp của tôi là trực tiếp mở rộng UINavigationControllerlớp:

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
    }

}

Bằng cách này, tất cả các bộ điều khiển điều hướng sẽ có thể bị loại bỏ bằng cách trượt.


Điều kỳ lạ là điều này khiến tất cả các viewDidAppearcuộc gọi trên VC thuộc bất kỳ bộ điều khiển điều hướng nào bị bỏ qua.
cumanzor

4

Bạn có thể làm điều đó với Proxy Delegate. Khi bạn đang xây dựng bộ điều khiển điều hướng, hãy lấy đại biểu hiện có. Và chuyển nó vào proxy. Sau đó, chuyển tất cả các phương thức ủy quyền cho đại biểu hiện có ngoại trừgestureRecognizer:shouldReceiveTouch: việc sử dụngforwardingTargetForSelector:

Thiết lập:

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

Ủy quyền ủy quyền:

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
    }  
}

Câu trả lời này là đúng kiểu Obj-C!
Sound Blaster

forwardingTargetForSelector sẽ giúp tôi tiết kiệm rất nhiều thời gian cho một dự án trước đây nếu tôi biết về nó. Đồ tốt!
VaporwareWolf

4

Câu trả lời của Hunter Monk thực sự tuyệt vời, nhưng tiếc là trong iOS 13.3.1, nó không hoạt động.

Tôi sẽ giải thích một cách khác để ẩn UINavigationBarvà không bị mất swipe to back gesture. Tôi đã thử nghiệm trên iOS 13.3.1 và 12.4.3 và nó hoạt động.

Bạn cần tạo một lớp tùy chỉnh UINavigationControllervà đặt lớp đó UINavigationControllertrongStoryboard

Đặt lớp tùy chỉnh thành <code> UINavigationController </code>

KHÔNG ẩn NavigationBartrênStoryboard

<code> UINavigationController </code> Trình kiểm tra thuộc tính:

Ví dụ trên Storyboard:

Bảng phân cảnh:

Và cuối cùng, hãy đặt này: navigationBar.isHidden = truetrong viewDidLoadcác CustomNavigationControllerlớp học.

Hãy chắc chắn rằng, KHÔNG sử dụng phương pháp này setNavigationBarHidden(true, animated: true)để ẩn NavigationBar.

import UIKit

class CustomNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationBar.isHidden = true
    }
}

2
Tôi đã thử nghiệm điều này trên thiết bị thực là iPhone 6S Plus với iOS 13.4.1thao tác vuốt ngược.
Emre Aydin

1
cũng hoạt động trên iOS 14.0.1 mới nhất
bezoadam

1

Xamarin Trả lời:

Triển khai IUIGestureRecognizerDelegateGiao diện trong định nghĩa Lớp của ViewController của bạn:

public partial class myViewController : UIViewController, IUIGestureRecognizerDelegate

Trong ViewController của bạn, hãy thêm phương thức sau:

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

Trong ViewController của bạn, hãy ViewDidLoad()thêm dòng sau:

NavigationController.InteractivePopGestureRecognizer.Delegate = this;

Có lẽ đây là trong UINavigationControllerbộ điều khiển chế độ xem gốc của? Tôi nhận được EXEC_BAD_ACCESSkhi tôi thử điều này.
Benjohn

Bạn có thể xoay cạnh trên bộ điều khiển chế độ xem gốc? Đó không phải là có thể bởi vì khi bạn đang ở thư mục gốc VC bạn đã popped tất cả VCs khác, và độ dài của mảng VC Nav của bạn nên được 1.
Ahmad

Sự cố xảy ra trước cuộc gọi tới gestureRecognizerShouldBegin:.
Benjohn

1
Bạn có thể đăng mã VC của mình trong một Câu hỏi mới hoặc trên các diễn đàn Xamarin không?
Ahmad

Không, tôi không. Tôi nghĩ tôi sẽ để nó cho .1!
Benjohn

1

Tôi đã thử điều này và nó hoạt động hoàn hảo: Cách ẩn Thanh điều hướng mà không làm mất khả năng trượt lại

Ý tưởng là triển khai "UIGestureRecognizerDelegate" trong tệp .h của bạn và thêm tệp này vào tệp .m của bạn.

- (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

Đây là giải pháp của tôi: Tôi đang thay đổi alpha trên thanh điều hướng, nhưng thanh điều hướng không bị ẩn. Tất cả các bộ điều khiển chế độ xem của tôi là một lớp con của BaseViewController của tôi và ở đó tôi có:

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

Bạn cũng có thể phân lớp UINavigationController và đặt phương thức đó ở đó.


0

Một số người đã thành công khi gọi setNavigationBarHiddenphương thức bằng hoạt ảnh YES.


Tôi đã cố gắng không may mắn. Cập nhật câu trả lời của tôi để bao gồm đề xuất này.
mihai

0

Trong bộ điều khiển chế độ xem của tôi không có thanh điều hướng, tôi sử dụng

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()
}

Tuy nhiên, trong quá trình loại bỏ tương tác, nút quay lại sẽ sáng lên, đó là lý do tại sao tôi đã ẩn nó.


-2

Có một giải pháp thực sự đơn giản mà tôi đã thử và hoạt động hoàn hảo, đây là trong Xamarin.iOS nhưng cũng có thể áp dụng cho bản địa:

    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

Dưới đây là cách tắt trình nhận dạng cử chỉ khi người dùng trượt ra khỏi ViewController. Bạn có thể dán nó trên viewWillAppear () hoặc trên các phương thức ViewDidLoad () của bạn.

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

Vui lòng đọc câu hỏi trước khi đăng câu trả lời. Câu hỏi là về việc kích hoạt nó, không phải tắt nó. CHÚNG TÔI YÊU THƯƠNG HIỆU POP.
Yogesh Maheshwari
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.