web-dev-qa-db-fra.com

Création d'un bouton avec une flèche vers la gauche (comme le style "retour" de UINavigationBar) sur une barre UIToolbar

J'aimerais créer un bouton "précédent" dans la partie gauche de la flèche vers la gauche dans un UIToolbar.

Autant que je sache, le seul moyen d’obtenir l’un d’eux est de laisser UINavigationController aux réglages par défaut et d’en utiliser un pour l’élément de barre de gauche. Mais je ne peux pas en créer un en tant que UIBarButtonItem, donc je ne peux pas en créer un dans un UIToolbar standard, même s'ils sont très similaires à UINavigationBars.

Je pouvais le créer manuellement avec des images de boutons, mais je ne peux trouver les images sources nulle part. Ils ont des bords de canal alpha, de sorte que les captures d'écran et les découpages n'obtiendront pas des résultats très polyvalents.

Des idées autres que la capture d'écran pour chaque taille et palette de couleurs que je compte utiliser?

Mise à jour: VEUILLEZ CESSER d’éviter la question et de suggérer que je ne devrais pas poser cette question et que je devrais utiliser UINavigationBar. Mon application est Instapaper Pro. Il affiche uniquement une barre d'outils inférieure (pour économiser de l'espace et maximiser la zone de contenu lisible), et je souhaite placer un bouton Précédent en forme de flèche vers la gauche dans le bas.

Me dire que je ne devrais pas avoir besoin de faire cela n'est pas une réponse et ne mérite certainement pas une prime.

289
Marco

J'ai utilisé le psd suivant dont j'ai dérivé http://www.teehanlax.com/blog/?p=447

http://www.chrisandtennille.com/pictures/backbutton.psd

Je viens alors de créer un UIView personnalisé que j'utilise dans la propriété customView de l'élément de la barre d'outils.

Fonctionne bien pour moi.


Edit: Comme indiqué par PrairieHippo , maralbjo a constaté que l'utilisation du code suivant, simple, faisait l'affaire (nécessite une image personnalisée dans un ensemble) doit être combinée avec cette réponse. Donc, voici du code supplémentaire:

// Creates a back button instead of default behaviour (displaying title of previous screen)
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back_arrow.png"]
                                                               style:UIBarButtonItemStyleBordered
                                                              target:self
                                                              action:@selector(backAction)];

tipsDetailViewController.navigationItem.leftBarButtonItem = backButton;
[backButton release];
129
PyjamaSam

La méthode Unicode

Je pense qu'il est beaucoup plus facile d'utiliser simplement un caractère Unicode pour faire le travail. Vous pouvez regarder à travers les flèches en recherchant Google triangles Unicode ou Unicode . À partir de iOS6, Apple a modifié le caractère afin qu’il s’agisse d’un caractère emoji avec une bordure. Pour désactiver la bordure, j'ajoute le sélecteur de variation Unicode 0xFE0E .

NSString *backArrowString = @"\U000025C0\U0000FE0E"; //BLACK LEFT-POINTING TRIANGLE PLUS VARIATION SELECTOR

UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.leftButtonItem = backBarButtonItem;

Le bloc de code est juste pour la démo. Cela fonctionnerait dans n'importe quel bouton qui accepte un NSString.

Pour obtenir une liste complète des caractères, recherchez sur Google un caractère Unicode et ce que vous voulez. Voici l'entrée pour Triangle de pointage gauche noir .

Résultat

The result

46

ATTENTION: Il a été signalé que cela ne fonctionnerait pas sur iOS 6. Cela pourrait ne fonctionner que sur les anciennes versions du système d'exploitation. De toute évidence, au moins un développeur a vu son application rejetée pour utiliser cette astuce (voir les commentaires). À utiliser à vos risques et périls. L'utilisation d'une image (voir la réponse ci-dessus) pourrait constituer une solution plus sûre.

Cela peut être fait sans ajouter vos propres fichiers image en utilisant le type de bouton 101 de sekr1t pour obtenir la forme correcte. Pour moi, le truc était de comprendre que je pouvais utiliser initWithCustomView pour créer le BarButtonItem. Personnellement, j’en avais besoin pour une barre de navigation dynamique plutôt que pour une toolbar, mais je l’ai testée avec une barre d’outils et le code est presque le même:

// create button
UIButton* backButton = [UIButton buttonWithType:101]; // left-pointing shape!
[backButton addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside];
[backButton setTitle:@"Back" forState:UIControlStateNormal];

// create button item -- possible because UIButton subclasses UIView!
UIBarButtonItem* backItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];

// add to toolbar, or to a navbar (you should only have one of these!)
[toolbar setItems:[NSArray arrayWithObject:backItem]];
navItem.leftBarButtonItem = backItem;

Si vous faites cela dans une barre d’outils, vous devrez modifier comment vous définissez les éléments, mais cela dépend du reste de votre code et je laisse cela comme un exercice pour le lecteur. : P Cet échantillon a fonctionné pour moi (compilé et exécuté).

Blah blah, lisez le HIG, n'utilisez pas de fonctionnalités non documentées, etc. Il n'y a que six types de boutons pris en charge et ce n'est pas l'un d'entre eux.

37
AndrewS

enter image description here

Tout d'abord, vous devez trouver une image du bouton de retour. J'ai utilisé une application appelée Nice Extractor qui extrait tous les graphiques de l'iPhone. Dans iOS7 , j'ai réussi à récupérer l'image appelée UINavigationBarBackIndicatorDefault et elle était de couleur noire, car j'avais besoin d'une teinte rouge. Je change la couleur en rouge en utilisant Gimp.

EDIT:

Comme mentionné par btate dans son commentaire, il n'est pas nécessaire de changer la couleur avec l'éditeur d'image. Le code suivant devrait faire l'affaire:

imageView.tint = [UIColor redColor];
imageView.image = [[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

Ensuite, j'ai créé une vue contenant une image avec cette flèche, une étiquette avec le texte personnalisé et en haut de la vue, un bouton avec une action. Ensuite, j'ai ajouté une animation simple (fondu et traduction).

Le code suivant simule le comportement du bouton Précédent, y compris l'animation.

-(void)viewWillAppear:(BOOL)animated{
        UIImageView *imageView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"]];
        [imageView setTintColor:[UIColor redColor]];
        UILabel *label=[[UILabel alloc] init];
        [label setTextColor:[UIColor redColor]];
        [label setText:@"Blog"];
        [label sizeToFit];

        int space=6;
        label.frame=CGRectMake(imageView.frame.Origin.x+imageView.frame.size.width+space, label.frame.Origin.y, label.frame.size.width, label.frame.size.height);
        UIView *view=[[UIView alloc] initWithFrame:CGRectMake(0, 0, label.frame.size.width+imageView.frame.size.width+space, imageView.frame.size.height)];

        view.bounds=CGRectMake(view.bounds.Origin.x+8, view.bounds.Origin.y-1, view.bounds.size.width, view.bounds.size.height);
        [view addSubview:imageView];
        [view addSubview:label];

        UIButton *button=[[UIButton alloc] initWithFrame:view.frame];
        [button addTarget:self action:@selector(handleBack:) forControlEvents:UIControlEventTouchUpInside];
        [view addSubview:button];

        [UIView animateWithDuration:0.33 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
            label.alpha = 0.0;
            CGRect orig=label.frame;
            label.frame=CGRectMake(label.frame.Origin.x+25, label.frame.Origin.y, label.frame.size.width, label.frame.size.height);
            label.alpha = 1.0;
            label.frame=orig;
        } completion:nil];

        UIBarButtonItem *backButton =[[UIBarButtonItem alloc] initWithCustomView:view];
}

- (void) handleBack:(id)sender{
}

EDIT:

À mon avis, au lieu d’ajouter le bouton, la meilleure approche consiste à utiliser un dispositif de reconnaissance des gestes.

UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBack:)];
[view addGestureRecognizer:tap];
[view setUserInteractionEnabled:YES];
36
Alexey

Je ne sais pas si cela fonctionnerait, mais vous pouvez essayer de créer un UINavigationController avec les paramètres par défaut pour créer le bouton, trouver le bouton dans la hiérarchie de sous-vues du contrôleur de navigation, appeler removeFromSuperview, détruire le contrôleur de navigation, puis ajoutez le bouton en tant que sous-vue de votre barre d’outils. Vous devrez peut-être également utiliser retain et le bouton avant d'appeler removeFromSuperview (puis release après l'avoir ajouté en tant que sous-vue de votre barre d'outils) pour éviter sa désallocation au cours du processus.

18
Adam Rosenfield

Pour créer un bouton UIB avec une flèche assez proche (je ne suis pas un concepteur;) de la flèche arrière du système iOS 7:

La norme:

Standard system back arrow

Apple SD Gothic Neo

Apple SD Gothic Neo < character

Dans Xcode:

  • Concentrez-vous sur le champ de valeur du titre du bouton (ou sur toute autre vue/commande avec du texte)
  • Ouvrez Édition -> Caractères spéciaux
  • Sélectionnez le groupe de parenthèses et double-cliquez sur le caractère '<'
  • Remplacez la police de caractères par: Apple SD Gothic Neo, Normal à la taille souhaitée (par exemple 20)
  • Changez de couleur à votre guise

Réf réponse de @ staticVoidMan à la flèche semblable à celle du dos sur iOS 7

14
Bjørn Egil

back arrow

Si vous ne voulez pas vous soucier des fichiers image, la forme de flèche peut être dessinée dans une sous-classe UIView avec le code suivant:

- (void)drawRect:(CGRect)rect {
    float width = rect.size.width;
    float height = rect.size.height;
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextBeginPath(context);
    CGContextMoveToPoint(context, width * 5.0/6.0, height * 0.0/10.0);
    CGContextAddLineToPoint(context, width * 0.0/6.0, height * 5.0/10.0);
    CGContextAddLineToPoint(context, width * 5.0/6.0, height * 10.0/10.0);
    CGContextAddLineToPoint(context, width * 6.0/6.0, height * 9.0/10.0);
    CGContextAddLineToPoint(context, width * 2.0/6.0, height * 5.0/10.0);
    CGContextAddLineToPoint(context, width * 6.0/6.0, height * 1.0/10.0);
    CGContextClosePath(context);

    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextFillPath(context);
}

où la flèche est proportionnelle à une largeur de 6,0 et à une hauteur de 10,0

8
machoota
    self.navigationItem.leftBarButtonItem = self.navigationItem.backBarButtonItem;

Travaille pour moi. J'utilisais cela quand j'avais plus d'onglets que je pouvais tenir dans la barre d'onglets, et un contrôleur de vue poussé depuis le "Plus" remplaçait le leftBarButtonItem dans son viewDidLoad.

7
quantumpotato

Voici ce que j'ai fini par faire après avoir recherché toutes ces solutions et d'autres. Il utilise un fichier png extensible extrait des images de stock UIKit. De cette façon, vous pouvez définir le texte comme bon vous semble

// Generate the background images
UIImage *stretchableBackButton = [[UIImage imageNamed:@"UINavigationBarDefaultBack.png"] stretchableImageWithLeftCapWidth:14 topCapHeight:0];
UIImage *stretchableBackButtonPressed = [[UIImage imageNamed:@"UINavigationBarDefaultBackPressed.png"] stretchableImageWithLeftCapWidth:13 topCapHeight:0];
// Setup the UIButton
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setBackgroundImage:stretchableBackButton forState:UIControlStateNormal];
[backButton setBackgroundImage:stretchableBackButtonPressed forState:UIControlStateSelected];
NSString *buttonTitle = NSLocalizedString(@"Back", @"Back");
[backButton setTitle:buttonTitle forState:UIControlStateNormal];
[backButton setTitle:buttonTitle forState:UIControlStateSelected];
backButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 2, 1); // Tweak the text position
NSInteger width = ([backButton.titleLabel.text sizeWithFont:backButton.titleLabel.font].width + backButton.titleEdgeInsets.right +backButton.titleEdgeInsets.left);
[backButton setFrame:CGRectMake(0, 0, width, 29)];
backButton.titleLabel.font = [UIFont boldSystemFontOfSize:13.0f];
[backButton addTarget:self action:@selector(yourSelector:) forControlEvents:UIControlEventTouchDown];
// Now add the button as a custom UIBarButtonItem
UIBarButtonItem *backButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:backButton] autorelease];
self.navigationItem.leftBarButtonItem = backButtonItem;
4
Steve

La bibliothèque Three20 a un moyen de le faire:

  UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle: @"Title" style:UIBarButtonItemStylePlain 
                                                                target:self action:@selector(foo)];

  UIColor* darkBlue = RGBCOLOR(109, 132, 162);

  TTShapeStyle* style = [TTShapeStyle styleWithShape:[TTRoundedLeftArrowShape shapeWithRadius:4.5] next:
    [TTShadowStyle styleWithColor:RGBCOLOR(255,255,255) blur:1 offset:CGSizeMake(0, 1) next:
    [TTReflectiveFillStyle styleWithColor:darkBlue next:
    [TTBevelBorderStyle styleWithHighlight:[darkBlue shadow]
                                     shadow:[darkBlue multiplyHue:1 saturation:0.5 value:0.5]
                                      width:1 lightSource:270 next:
    [TTInsetStyle styleWithInset:UIEdgeInsetsMake(0, -1, 0, -1) next:
    [TTBevelBorderStyle styleWithHighlight:nil shadow:RGBACOLOR(0,0,0,0.15)
                                        width:1 lightSource:270 next:nil]]]]]];

  TTView* view = [[[TTView alloc] initWithFrame:CGRectMake(0, 0, 80, 35)] autorelease];
  view.backgroundColor = [UIColor clearColor];
  view.style = style;
  backButton.customView = view;


  self.navigationItem.leftBarButtonItem = backButton;
4
Andrew Arrow

J'ai constaté que le code suivant permettait de résoudre ce problème (nécessite une image personnalisée en lot):

// Creates a back button instead of default behaviour (displaying title of previous screen)
    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back_arrow.png"]
                                                                   style:UIBarButtonItemStyleBordered
                                                                  target:self
                                                                  action:@selector(backAction)];

    tipsDetailViewController.navigationItem.leftBarButtonItem = backButton;
    [backButton release];
4
maralbjo

Vous pouvez trouver les images sources en les extrayant de Other.artwork dans UIKit $ {SDKROOT} /System/Library/Frameworks/UIKit.framework/Other.artwork. La communauté de modding a quelques outils pour les extraire, here . Une fois que vous extrayez l'image, vous pouvez écrire du code pour le recolorer au besoin et le définir comme image du bouton. Que vous puissiez ou non envoyer une telle chose (puisque vous intégrez des œuvres d'art dérivées) est peut-être un peu risqué, alors vous voudrez peut-être parler à un avocat.

4
Louis Gerbarg

C'est facile à faire avec Interface Builder in Xcode 5.x

Result

  • utiliser barre d'outils et élément de bouton de barre à partir de bibliothèque d'objets

    Components

  • dans le bouton Inspecteur d'attributs modifier Image section avec votre retour image du bouton

    Attributes inspector

Fait!

4
Anton Gaenko

J'essayais de faire la même chose, mais je voulais que le bouton Précédent se trouve dans la barre de navigation. (J'avais en fait besoin d'un bouton de retour, ce qui ferait plus que simplement revenir en arrière, j'ai donc dû utiliser la propriété leftBarButtonItem). J'ai essayé ce qu'AndrewS avait suggéré, mais dans la barre de navigation, cela ne ressemblait pas à ce qu'il devrait être, car UIButton était en quelque sorte jeté sur un UIBarButtonItem.

Mais j'ai trouvé un moyen de contourner ce problème. En fait, je viens de mettre UIView sous UIButton et de définir customView pour UIBarButtonItem. Voici le code, si quelqu'un en a besoin:

// initialize button and button view
UIButton *backButton = [UIButton buttonWithType:101];
UIView *backButtonView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, backButton.frame.size.width, backButton.frame.size.height)];

[backButton addTarget:self action:@selector(backButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
[backButton setTitle:@"Back" forState:UIControlStateNormal];
[backButtonView addSubview:backButton];

// set buttonview as custom view for bar button item
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButtonView];
self.navigationItem.leftBarButtonItem = backButtonItem;

// Push item to navigationbar items
[self.navigationController.navigationBar setItems:[NSArray arrayWithObject:backButtonItem]];
2
marikaner

Pour créer une image pour la barre UIToolbar, créez un fichier png dans photoshop et WHERE EVER, quelle que soit la couleur, il le met en blanc, et où il est alpha = 0, il le laisse seul.

Le SDK a en fait placé la bordure autour de l'icône que vous avez créée et la rend blanche sans que vous n'ayez rien à faire.

Vous voyez, c’est ce que j’ai fait dans Photoshop pour mon bouton suivant (évidemment le permuter pour un bouton précédent):

http://twitpic.com/1oanv

et voici à quoi il ressemblait dans Interface Builder

http://twitpic.com/1oaoa

1
Domness

Solution SANS utiliser un png. Sur la base de cette SO réponse: Ajout de la petite flèche située à droite d'une cellule dans une cellule TableView de l'iPhone

Il suffit de basculer la UITableViewCell horizontalement!

UIButton *btnBack = [[UIButton alloc] initWithFrame:CGRectMake(0, 5, 70, 20)];

// Add the disclosure
CGRect frm;
UITableViewCell *disclosure = [[UITableViewCell alloc] init];
disclosure.transform = CGAffineTransformScale(CGAffineTransformIdentity, -1, 1);
frm = self.btnBack.bounds;
disclosure.frame = CGRectMake(frm.Origin.x, frm.Origin.y, frm.size.width-25, frm.size.height);
disclosure.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
disclosure.userInteractionEnabled = NO;
[self.btnBack addSubview:disclosure];

// Add the label
UILabel *lbl = [[UILabel alloc] init];
frm = CGRectOffset(self.btnBack.bounds, 15, 0);
lbl.frame = frm;
lbl.textAlignment = NSTextAlignmentCenter;
lbl.text = @"BACK";
[self addSubview:lbl];
1
Gabriel Jensen

Exemple dans Swift 3, avec un bouton précédent et un bouton suivant en haut à droite.

let prevButtonItem = UIBarButtonItem(title: "\u{25C0}", style: .plain, target: self, action: #selector(prevButtonTapped))
let nextButtonItem = UIBarButtonItem(title: "\u{25B6}", style: .plain, target: self, action: #selector(nextButtonTapped))
self.navigationItem.rightBarButtonItems = [nextButtonItem, prevButtonItem]
0
Bart van Kuik

Eh bien, vous n'avez pas besoin d'un bouton différent pour chaque taille, vous pouvez utiliser [UIImage stretchableImageWithLeftCapWidth:topCapHeight:], mais la seule chose que j'ai trouvée est des images personnalisées.

0
Ben Gottlieb

Swift

// create button
    var backButton = UIButton(type: 101)

    // left-pointing shape!
    backButton.addTarget(self, action: #selector(self.backAction), for: .touchUpInside)
    backButton.setTitle("Back", for: .normal)

    // create button item -- possible because UIButton subclasses UIView!
    var backItem = UIBarButtonItem(customView: backButton)

    // add to toolbar, or to a navbar (you should only have one of these!)
    toolbar.items = [backItem]
    navItem.leftBarButtonItem = backItem
0
user7587085

J'ai eu un problème similaire, et viens une bibliothèque PButton . Et l'exemple est le bouton de navigation arrière comme le bouton, qui peut être utilisé n'importe où, tout comme un bouton personnalisé.

Quelque chose comme ça: enter image description here

0
Shuo

Si vous souhaitez éviter de le dessiner vous-même, vous pouvez utiliser la classe non documentée: UINavigationButton avec le style 1. Cela peut, bien sûr, empêcher votre demande d'être approuvée .../John

0
John Lane