【问题标题】:Custom back button title and keep the swipe back gesture自定义后退按钮标题并保持向后滑动手势
【发布时间】:2023-03-27 10:04:01
【问题描述】:

问题: 我想在弹出的视图控制器中自定义导航返回按钮标题,例如 Whatsapp (

但是,如果您使用

,在弹出的视图控制器中分配一个新的 backBarButtonItem 将禁用向后滑动手势
self.navigationController.interactivePopGestureRecognizer.delegate = self;

为了保持手势工作,它会给你带来更多的麻烦(太多的错误)。

【问题讨论】:

标签: ios ios7 uinavigationcontroller uibarbuttonitem


【解决方案1】:

您必须在ViewController 上设置self.navigationItem.backBarButtonItem 属性,然后才能显示标题。

在 Whatsapp 示例中,您必须在聊天列表视图控制器上设置标题。

类似的东西:

self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"chats(2)" style:UIBarButtonItemStylePlain target:nil action:nil];

之后,您可以只设置self.navigationItem.backBarButtonItemtitle

【讨论】:

  • 我之前试过,self.navigationItem.backBarButtonItem是一个nil对象。
  • 是的,你是对的。我已经编辑了答案,现在应该可以了!
  • 不...它不起作用,如果您在第一个视图控制器中分配 backBarButtonItem,则在推送到第二个视图控制器后,backBarButtonItem 将再次变为 nil,即使您在 prepareForSegue 方法或只是分配它就像我在自定义导航控制器中的回答一样。这就是为什么我把它作为公共财产。
  • 只是为了确定,您正在第一个视图控制器上设置按钮。但是您将按钮设置在self,而不是segue.destinationViewController,对吧?
  • viewController.navigationItem.backBarButtonItem = backButton; 应该是目标视图控制器。
【解决方案2】:

如果您想在整个应用程序中清空后退按钮标题,一种解决方案是调配 viewDidLoad 并在调配后的 viewDidLoad 中清空后退按钮标题。 并且不会影响interactivePopGestureRecognizer的工作(确保interactivePopGestureRecognizer开启)。

            @implementation UIViewController (Customizations)

            + (void)load {
                static dispatch_once_t onceToken;
                dispatch_once(&onceToken, ^{
                    [UIViewController swizzleClass:[UIViewController class] method:@"viewDidLoad"];
                });
            }

            + (void)swizzleClass:(Class)class method:(NSString*)methodName {
                SEL originalMethod = NSSelectorFromString(methodName);
                SEL newMethod = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"override_", methodName]);
                [self swizzle:class from:originalMethod to:newMethod];
            }

            + (void)swizzle:(Class)class from:(SEL)original to:(SEL)new {
                Method originalMethod = class_getInstanceMethod(class, original);
                Method newMethod = class_getInstanceMethod(class, new);
                if(class_addMethod(class, original, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
                    class_replaceMethod(class, new, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
                } else {
                    method_exchangeImplementations(originalMethod, newMethod);
                }
            }

            - (void)override_viewDidLoad {
                //Empty back button title
                UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
                [self.navigationItem setBackBarButtonItem:backButtonItem];
                [self override_viewDidLoad];
            }

            @end

【讨论】:

  • 谢谢,你拯救了我的一天
【解决方案3】:

对于只想使用 UINavigationController 并修复此问题的人。我在 Swift 中为 UINavigationController 编写了一个扩展。

不存在快滑回会断栈的问题。

extension UINavigationController: UINavigationControllerDelegate, UIGestureRecognizerDelegate {

    public override static func initialize() {
        struct Static {
            static var token: dispatch_once_t = 0
        }

        if self !== UINavigationController.self {
            return
        }

        dispatch_once(&Static.token) {

            // Swizzle viewDidLoad

            self.swizzleViewDidLoad()

            // Swizzle pushViewController

            self.swizzlePushController()
        }
    }

    // MARK: - Helpers

    static func swizzleViewDidLoad() {
        let originalViewDidLoadSelector = #selector(UINavigationController.viewDidLoad)
        let swizzledViewDidLoadSelector = #selector(UINavigationController.newViewDidLoad)

        let originalViewDidLoadMethod = class_getInstanceMethod(self, originalViewDidLoadSelector)
        let swizzledViewDidLoadMethod = class_getInstanceMethod(self, swizzledViewDidLoadSelector)

        let didAddViewDidLoadMethod = class_addMethod(self, originalViewDidLoadSelector, method_getImplementation(swizzledViewDidLoadMethod), method_getTypeEncoding(swizzledViewDidLoadMethod))

        if didAddViewDidLoadMethod {
            class_replaceMethod(self, swizzledViewDidLoadSelector, method_getImplementation(originalViewDidLoadMethod), method_getTypeEncoding(swizzledViewDidLoadMethod))
        } else {
            method_exchangeImplementations(originalViewDidLoadMethod, swizzledViewDidLoadMethod);
        }
    }

    static func swizzlePushController() {
        let originalPushControllerSelector = #selector(UINavigationController.pushViewController(_:animated:))
        let swizzledPushControllerSelector = #selector(UINavigationController.newPushViewController(_:animated:))

        let originalPushControllerMethod = class_getInstanceMethod(self, originalPushControllerSelector)
        let swizzledPushControllerMethod = class_getInstanceMethod(self, swizzledPushControllerSelector)

        let didAddPushControllerMethod = class_addMethod(self, originalPushControllerSelector, method_getImplementation(swizzledPushControllerMethod), method_getTypeEncoding(swizzledPushControllerMethod))

        if didAddPushControllerMethod {
            class_replaceMethod(self, swizzledPushControllerSelector, method_getImplementation(originalPushControllerMethod), method_getTypeEncoding(swizzledPushControllerMethod))
        } else {
            method_exchangeImplementations(originalPushControllerMethod, swizzledPushControllerMethod);
        }
    }

    // MARK: - Method Swizzling

    func newViewDidLoad() {
        self.newViewDidLoad()

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

    func newPushViewController(viewController: UIViewController, animated: Bool) {
        self.interactivePopGestureRecognizer?.enabled = false

        self.newPushViewController(viewController, animated: animated)
    }

    // MARK: - UINavigationControllerDelegate

    public func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
        self.interactivePopGestureRecognizer?.enabled = true
    }
}

【讨论】:

    【解决方案4】:

    答案:

    花了一天的时间解决这个问题,我有一个非常简单易用的解决方案,适用于 iOS 6 和 iOS 7:

    1)。 AppDelegate 中的自定义样式(颜色、字体)(假设您将为所有控制器使用相同的样式)

    2)。像这样创建一个自定义 UINavigationController:

    CustomBackNavigationController.h

    @interface CustomBackNavigationController : UINavigationController <UINavigationControllerDelegate>
    
    @property (nonatomic, strong) UIBarButtonItem *backButton;
    
    @end
    

    CustomBackNavigationController.m

    @implementation CustomBackNavigationController
    
    @synthesize backButton;
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.delegate = self;
    }
    
    
    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        backButton = [[UIBarButtonItem alloc] initWithTitle:@"Chats" style:UIBarButtonItemStyleBordered target:nil action:nil];
        viewController.navigationItem.backBarButtonItem = backButton;
    }
    
    @end
    

    在弹出的视图控制器中,只需像这样更改 backButton 标题

    - (void)someMethod
    {
        CustomBackNavigationController *customBackNavigationController = (CustomBackNavigationController *) self.navigationController;
    
        [customBackNavigationController.backButton setTitle:@"Chats (1)"];
    }
    

    就是这样!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-30
      • 2020-01-07
      • 2013-09-23
      • 1970-01-01
      • 2021-08-17
      相关资源
      最近更新 更多