自定义后退按钮标题并保持向后滑动手势

问题:我想在弹出的视图控制器中自定义导航后退按钮标题,如Whatsapp(<Chats(2)/ <Chats(3))。

但是,如果您使用弹出视图控制器中的新backBarButtonItem将禁用滑动后退手势

self.navigationController.interactivePopGestureRecognizer.delegate = self; 

为了保持手势的有效,它会给你带来更多麻烦(太多bugssss)。

您必须在ViewController上设置self.navigationItem.backBarButtonItem属性,该属性将在显示标题之前出现。

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

像这样的东西:

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

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

如果你想在整个应用程序中清空后退按钮标题,其中一个解决方案是在swizzled 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 

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

它没有问题,如果您快速刷回堆栈可能会被打破。

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

回答:

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

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

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

CustomBackNavigationController.h

 @interface CustomBackNavigationController : UINavigationController  @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)"]; } 

而已 !