web-dev-qa-db-fra.com

Bouton de retour personnalisé dans UINavigationController

Pour une application que je développe, je dois afficher un bouton Précédent personnalisé dans une barre de navigation. J'ai l'actif du bouton sous forme d'image PNG et j'écris ce code:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
    backButton.frame = CGRectMake(0, 0, 79, 29.0);
    [backButton setImage:[UIImage imageNamed:@"button_back.png"] forState:UIControlStateNormal];
    self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:backButton] autorelease];

}

Lorsque j'appuie sur ce contrôleur de vue, le bouton personnalisé n'apparaît pas et je reçois à la place le bouton retour standard avec le titre de ce contrôleur de vue à l'intérieur.

Choses que j'ai déjà essayées:

  1. Vérifiez que le bouton backButton est créé correctement en l’ajoutant à la hiérarchie des vues. Il affiche correctement.
  2. Dans la même méthode, modifiez la propriété title de la navigationItem et confirmez qu'elle modifie (comme prévu) le contenu de mon bouton de retour.

Quelqu'un peut-il repérer ce que je fais mal? Quelqu'un at-il réussi à utiliser une image personnalisée comme bouton de retour avec une variable UINavigationController?

17
pgb

La propriété backBarButtonItem fonctionne comme prévu, mais elle ajoutera toujours sa forme et sa couleur de bouton standard en fonction de la couleur de la teinte de la barre de navigation.

Vous pouvez personnaliser le texte, mais pas remplacer l'image.

Une solution de rechange, comme l'a suggéré Andrew Pouliot, consiste à utiliser leftBarButtonItem à la place, mais je suis resté bloqué sur le bouton standard.

5
pgb

À partir de iOS 5, c'est simple:

[[UIBarButtonItem appearance]
            setBackButtonBackgroundImage:[UIImage imageNamed:@"back_button.png"]
            forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

Vous pouvez l'insérer dans le délégué de votre application pour définir l'image d'arrière-plan sur tous les boutons de retour de l'application (pour cet état de contrôle et cette mesure de barre, bien sûr).

18
Matías R

Je republie ma solution de https://stackoverflow.com/a/16831482/171933 :

Je crée une catégorie simple sur UIViewController:

UIViewController + ImageBackButton.h

#import <UIKit/UIKit.h>

@interface UIViewController (ImageBackButton)

- (void)setUpImageBackButton;

@end

UIViewController + ImageBackButton.m

#import "UIViewController+ImageBackButton.h"

@implementation UIViewController (ImageBackButton)

- (void)setUpImageBackButton
{
    UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 34, 26)];
    [backButton setBackgroundImage:[UIImage imageNamed:@"back_arrow.png"] forState:UIControlStateNormal];
    UIBarButtonItem *barBackButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    [backButton addTarget:self action:@selector(popCurrentViewController) forControlEvents:UIControlEventTouchUpInside];
    self.navigationItem.leftBarButtonItem = barBackButtonItem;
    self.navigationItem.hidesBackButton = YES;
}

- (void)popCurrentViewController
{
    [self.navigationController popViewControllerAnimated:YES];
}

@end

Tout ce que vous avez à faire est maintenant #import UIViewController+ImageBackButton.h dans tous vos contrôleurs de vue ou dans une classe de contrôleur de vue de base personnalisée dont vos autres contrôleurs de vue héritent et implémentent la méthode viewWillAppear::

- (void)viewWillAppear:(BOOL)animated
{
    [self setUpImageBackButton];
}

C'est tout. Maintenant, vous avez un bouton de retour d'image partout. Sans bordure. Prendre plaisir!

13

La solution la plus simple n’est-elle pas simplement de la concevoir à partir de votre scénario avec l’image ou les couleurs de votre choix et de faire simplement glisser une nouvelle action sur votre contrôleur?

Code rapide

@IBAction func backButton(sender: AnyObject) {
    self.navigationController?.popViewControllerAnimated(true)
}
4
vladCovaliov

Confusément, backBarButtonItem n'est pas ce que vous recherchez.

Il contrôle simplement le titre sur le bouton Précédent pour le prochain contrôleur de vue. Ce que vous voulez, c'est définir le leftBarButtonItem sur votre bouton retour personnalisé.

3
Andrew Pouliot

Voir cette réponse ici: Comment créer backBarButtomItem avec une vue personnalisée pour un UINavigationController

Il vous suffit de définir la propriété backBarButtonItem sur le navigationController before en poussant le viewController. La définition de la propriété backBarButtonItem dans la méthode viewDidLoad du viewController (par exemple) ne fonctionne pas.

1
SundayMonday

La réponse de Johannes Fahrenkrug fonctionne, mais l'image arrière apparaîtrait à une position très câblée.

Ici, j'ai trouvé un meilleur moyen de positionner l'image au bon endroit:

Assurez-vous d'avoir une image au format 24x24 (@ 1x), je l'appelle backImage

Exécutez le code suivant au lancement de votre application.

UINavigationBar.appearance().barTintColor = nil
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, -60), forBarMetrics: .Default)
1
duan

Je ne pense pas que ViewController lui-même ne devrait rien savoir de son bouton Précédent Selon OOP, cette responsabilité incombe à containerViewController dans lequel votre contrôleur de vue est inséré, par exemple UINavigationController.

Sous-classez votre NavigationController et surchargez-y la méthode superClass comme ceci:

@implementation STONavigationController

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [super pushViewController:viewController animated:animated];
    if ([self.viewControllers indexOfObject:viewController] != NSNotFound &&
        [self.viewControllers indexOfObject:viewController] > 0){
        UIImage *img = [UIImage imageNamed:@"back-1"];
        UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, img.size.width * 2, img.size.height * 2)];
        [backButton setBackgroundImage:img forState:UIControlStateNormal];
        UIBarButtonItem *barBackButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
        [backButton addTarget:self action:@selector(popCurrentViewController) forControlEvents:UIControlEventTouchUpInside];
        viewController.navigationItem.leftBarButtonItem = barBackButtonItem;
        viewController.navigationItem.hidesBackButton   = YES;
    }
}

- (void)popCurrentViewController
{
    [self popViewControllerAnimated:YES];
}

@end 
1
Nikolay Shubenkov

Comme @pgb l'a suggéré, vous pouvez utiliser leftBarButtonItem au lieu d'un élément du bouton Précédent. Et pour supprimer l’élément de bouton Précédent par défaut, définissez-le sur nil comme suit;

navigationController?.navigationBar.backIndicatorImage = nil
navigationController?.navigationBar.backIndicatorTransitionMaskImage = nil

let button = UIButton.init(type: .custom)
button.imageView?.contentMode = UIViewContentMode.scaleAspectFit
button.setImage(UIImage.init(named: "top_back"), for: UIControlState.normal)
button.frame = CGRect.init(x: 0, y: 0, width: 75, height: 50) 
button.addTarget(self, action: #selector(handleBackButton), for: .touchUpInside)

let barButton = UIBarButtonItem.init(customView: button)
self.navigationItem.leftBarButtonItem = barButton
0
Ammar Mujeeb

Créez simplement une UIBarButtonItem au lieu d'une UIButton incorporée dans UIBarButtonItem. Fonctionne bien!

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"button_back.png"] style:UIBarButtonItemStyleBordered target:nil action:nil];

self.navigationItem.backBarButtonItem = backButton; 
0
romrom