Персонализирано заглавие на бутона за връщане назад и запазване на жеста за плъзгане назад

Проблем: Бих искал да персонализирам заглавието на бутона за навигация назад в изскачащия контролер за изглед като Whatsapp ( ‹ Чатове (2) / ‹ Чатове (3) ).

Въпреки това, за да присвоите нов backBarButtonItem в изскачащия контролер за изглед, ще деактивирате жеста за плъзгане назад, ако използвате

self.navigationController.interactivePopGestureRecognizer.delegate = self;

за да продължи работата на жеста, това ще ви създаде повече неприятности (твърде много грешки).


person Rex Lam    schedule 20.05.2014    source източник
comment
Обърнете се към този stackoverflow.com/a/9871741/1707115   -  person Kaiusee    schedule 20.05.2014
comment
Написах бързо разширение, така че можете просто да добавите този файл и да използвате UINavigationController по подразбиране и трябва да работи. gist.github.com/donpironet/f5ce9857f422df46d52f053c22d96c8c   -  person user1007522    schedule 29.06.2016


Отговори (4)


Трябва да зададете свойството self.navigationItem.backBarButtonItem на ViewController, което идва преди това да покаже заглавието.

В примера с Whatsapp ще трябва да зададете заглавието на контролера за преглед на списъка с чатове.

Нещо такова:

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

След това можете да зададете само title от self.navigationItem.backBarButtonItem.

person Gonzo    schedule 20.05.2014
comment
Опитах го преди, self.navigationItem.backBarButtonItem е нулев обект. - person Rex Lam; 20.05.2014
comment
Да, прав си. Редактирах отговора, сега трябва да работи! - person Gonzo; 20.05.2014
comment
Не... не работи, ако присвоите backBarButtonItem в първия контролер за изглед, след натискане към втория контролер за изглед backBarButtonItem отново ще стане нула, дори да го присвоите в метода pripraveForSegue или точно като моя отговор в персонализиран контролер за навигация . Затова го направих обществена собственост. - person Rex Lam; 20.05.2014
comment
Само за да сте сигурни, вие настройвате бутона на първия контролер за изглед. Но вие задавате бутона на self, а не на segue.destinationViewController, нали? - person Gonzo; 20.05.2014
comment
viewController.navigationItem.backBarButtonItem = backButton; Трябва да е целевият изглед контролер. - person Rex Lam; 20.05.2014
comment
Първоначално може да изглежда контраинтуитивно, но това viewController трябва да е аз-ът на firstViewController. - person Gonzo; 20.05.2014
comment
Току-що проверено, това е дестинационен изглед контролер. Да, изглежда контраинтуитивно, аз също не разбирам това поведение - person Rex Lam; 20.05.2014

Ако искате да изпразните заглавието на бутона за връщане назад в цялото приложение, едно от решенията е да развъртите 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
person Narek Safaryan    schedule 27.01.2015
comment
Благодаря, спасихте деня ми - person xxi; 01.10.2018

За хора, които просто искат да използват UINavigationController и това да е поправено. Написах разширение за UINavigationController в Swift.

Няма проблемът, че купчината може да бъде счупена, ако плъзнете назад до скоро.

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
    }
}
person user1007522    schedule 29.06.2016

Отговор:

След като прекарах един ден за този проблем, имам доста просто и лесно решение, което работи както на 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)"];
}

Това е !

person Rex Lam    schedule 20.05.2014