web-dev-qa-db-fra.com

Comment ajouter du texte multiligne à un UIButton?

J'ai le code suivant...

UILabel *buttonLabel = [[UILabel alloc] initWithFrame:targetButton.bounds];
buttonLabel.text = @"Long text string";
[targetButton addSubview:buttonLabel];
[targetButton bringSubviewToFront:buttonLabel];

... l’idée étant que je peux avoir un texte multiligne pour le bouton, mais le texte est toujours masqué par l’image backgroundImage du bouton UIB. Un appel de journalisation pour afficher les sous-vues du bouton indique que le libellé UILabel a été ajouté, mais que le texte lui-même n’est pas visible. Est-ce un bug dans UIButton ou est-ce que je fais quelque chose de mal?

340
Owain Hunt

Pour iOS 6 et versions ultérieures, utilisez les éléments suivants pour autoriser plusieurs lignes:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
// you probably want to center it
button.titleLabel.textAlignment = NSTextAlignmentCenter; // if you want to 
[button setTitle: @"Line1\nLine2" forState: UIControlStateNormal];

Pour iOS 5 et versions antérieures, utilisez les éléments suivants pour autoriser plusieurs lignes:

button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
// you probably want to center it
button.titleLabel.textAlignment = UITextAlignmentCenter;
[button setTitle: @"Line1\nLine2" forState: UIControlStateNormal];

2017, pour iOS9 avant ,

généralement, il suffit de faire ces deux choses:

  1. choisissez "Texte attribué"
  2. dans le menu contextuel "Saut de ligne", sélectionnez "Retour à la ligne"
645
jessecurry

La réponse sélectionnée est correcte, mais si vous préférez procéder de la sorte dans Interface Builder, procédez comme suit:

pic

129
Adam Waite

Pour IOS 6:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;

Comme 

UILineBreakModeWordWrap and UITextAlignmentCenter

sont obsolètes à partir de IOS à partir de 6 ans.

53
NiKKi

Si vous souhaitez ajouter un bouton dont le titre est centré sur plusieurs lignes, définissez les paramètres de votre Interface Builder pour le bouton:

[here]

51
user5440039

Pour reformuler la suggestion de Roger Nolan, mais avec un code explicite, voici la solution générale:

button.titleLabel?.numberOfLines = 0
29
baudot

Swift 3

button.titleLabel?.lineBreakMode = .byWordWrapping
button.titleLabel?.textAlignment = .center  
button.setTitle("Button\nTitle",for: .normal)
20

Aligner à gauche sur iOS7 avec autolayout:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
11
neoneye

Il y a un moyen beaucoup plus facile:

someButton.lineBreakMode = UILineBreakModeWordWrap;

(Édition pour iOS 3 et versions ultérieures :)

someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
10
Valerii Hiora

Tout d’abord, vous devez savoir qu’UIButton contient déjà un UILabel. Vous pouvez le configurer en utilisant –setTitle:forState:.

Le problème de votre exemple est que vous devez définir la propriété numberOfLines de UILabel sur autre chose que sa valeur par défaut de 1. Vous devez également examiner la propriété lineBreakMode.

7
Rog

Les réponses fournies ici vous expliquent comment réaliser un titre de bouton multiligne par programme. 

Je voulais juste ajouter que si vous utilisez des storyboards, vous pouvez taper [Ctrl + Entrée] pour forcer une nouvelle ligne sur le champ du titre d'un bouton. 

HTH

4
user2338871

Pour ceux qui utilisent le storyboard de Xcode 4, vous pouvez cliquer sur le bouton. Dans le volet droit de la fenêtre Utilitaires, sous Inspecteur des attributs, vous verrez une option pour le saut de ligne. Choisissez Word Wrap, et vous devriez être prêt à partir.

4
Jack

Quant à l'idée de Brent de mettre le titre UILabel comme point de vue d'un frère, cela ne me semble pas une très bonne idée. Je continue de penser à des problèmes d'interaction avec UILabel en raison de ses événements tactiles qui ne parviennent pas à saisir le point de vue d'UIButton. 

D'autre part, avec un UILabel en tant que sous-vue de l'UIButton, je suis assez à l'aise sachant que les événements tactiles seront toujours propagés dans la vue d'ensemble de UILabel.

J'ai adopté cette approche et je n'ai remarqué aucun des problèmes signalés avec backgroundImage. J'ai ajouté ce code dans l'option -titleRectForContentRect: d'une sous-classe UIButton, mais le code peut également être placé dans la routine de dessin de la vue d'ensemble UIButton. Dans ce cas, vous devez remplacer toutes les références à self par la variable UIButton.

#define TITLE_LABEL_TAG 1234

- (CGRect)titleRectForContentRect:(CGRect)rect
{   
    // define the desired title inset margins based on the whole rect and its padding
    UIEdgeInsets padding = [self titleEdgeInsets];
    CGRect titleRect = CGRectMake(rect.Origin.x    + padding.left, 
                                  rect.Origin.x    + padding.top, 
                                  rect.size.width  - (padding.right + padding.left), 
                                  rect.size.height - (padding.bottom + padding].top));

    // save the current title view appearance
    NSString *title = [self currentTitle];
    UIColor  *titleColor = [self currentTitleColor];
    UIColor  *titleShadowColor = [self currentTitleShadowColor];

    // we only want to add our custom label once; only 1st pass shall return nil
    UILabel  *titleLabel = (UILabel*)[self viewWithTag:TITLE_LABEL_TAG];


    if (!titleLabel) 
    {
        // no custom label found (1st pass), we will be creating & adding it as subview
        titleLabel = [[UILabel alloc] initWithFrame:titleRect];
        [titleLabel setTag:TITLE_LABEL_TAG];

        // make it multi-line
        [titleLabel setNumberOfLines:0];
        [titleLabel setLineBreakMode:UILineBreakModeWordWrap];

        // title appearance setup; be at will to modify
        [titleLabel setBackgroundColor:[UIColor clearColor]];
        [titleLabel setFont:[self font]];
        [titleLabel setShadowOffset:CGSizeMake(0, 1)];
        [titleLabel setTextAlignment:UITextAlignmentCenter];

        [self addSubview:titleLabel];
        [titleLabel release];
    }

    // finally, put our label in original title view's state
    [titleLabel setText:title];
    [titleLabel setTextColor:titleColor];
    [titleLabel setShadowColor:titleShadowColor];

    // and return empty rect so that the original title view is hidden
    return CGRectZero;
}

J'ai pris le temps et écrit un peu plus à ce sujet ici . Là aussi, je pointe une solution plus courte, bien qu’elle ne convienne pas à tous les scénarios et implique quelques piratages de vues privées. Vous pouvez également télécharger une sous-classe UIButton prête à être utilisée.

3
jpedroso

Vous devez ajouter ce code:

buttonLabel.titleLabel.numberOfLines = 0;
3
Pablo Blanco

Si vous utilisez la disposition automatique sur iOS 6, vous devrez peut-être également définir la propriété preferredMaxLayoutWidth:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.titleLabel.preferredMaxLayoutWidth = button.frame.size.width;
2
vially

Si vous définissez lineBreakMode sur NSLineBreakByWordWrapping (en code IB ou en code), le libellé du bouton devient multiligne, mais n'affecte pas le cadre du bouton.

Si le bouton a un titre dynamique, il y a un truc: mettez UILabel caché avec la même police et liez sa hauteur à la hauteur du bouton avec layout; lorsque le texte est réglé sur bouton et étiquette et autolayout fera tout le travail.

Remarque

La taille de la taille intrinsèque du bouton à une ligne est supérieure à celle de l'étiquette. Par conséquent, pour éviter que la hauteur de l'étiquette ne soit réduite à la verticale, la priorité d'étanchement du contenu doit être supérieure à la résistance verticale du bouton.

2
Varrry

Si vous utilisez la mise en page automatique.

button.titleLabel?.adjustsFontSizeToFitWidth = true
button.titleLabel?.numberOfLines = 2
2
Sourabh Sharma

Ça fonctionne parfaitement.

Ajoutez à utiliser ceci avec le fichier de configuration comme Plist, vous devez utiliser CDATA pour écrire le titre multiliné, comme ceci:

<string><![CDATA[Line1
Line2]]></string>
2
makiko_fly

J'ai eu un problème avec la mise en page automatique, après avoir activé plusieurs lignes, le résultat était le suivant:
 enter image description here
afin que la taille titleLabel n'affecte pas la taille du bouton
J'ai ajouté Constraints basé sur contentEdgeInsets (dans ce cas, contentEdgeInsets était (10, 10, 10, 10)
après avoir appelé makeMultiLineSupport():
 enter image description here
espérons que cela vous aide (Swift 5.0):

extension UIButton {

    func makeMultiLineSupport() {
        guard let titleLabel = titleLabel else {
            return
        }
        titleLabel.numberOfLines = 0
        titleLabel.setContentHuggingPriority(.required, for: .vertical)
        titleLabel.setContentHuggingPriority(.required, for: .horizontal)
        addConstraints([
            .init(item: titleLabel,
                  attribute: .top,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .top,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.top),
            .init(item: titleLabel,
                  attribute: .bottom,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .bottom,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.bottom),
            .init(item: titleLabel,
                  attribute: .left,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .left,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.left),
            .init(item: titleLabel,
                  attribute: .right,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .right,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.right)
            ])
    }

}
1
Amir Khorsandi
self.btnError.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping

self.btnError.titleLabel?.textAlignment = .center

self.btnError.setTitle("Title", for: .normal)
0
Urvish Modi

Dans Swift 5.0 et Xcode 10.2

SharedClass example écrit une fois et utilise tous les articles

Ceci est votre classe partagée (comme cela vous utilisez toutes les propriétés des composants)

import UIKit

class SharedClass: NSObject {

     static let sharedInstance = SharedClass()

     private override init() {

     }
  }

//UIButton extension
extension UIButton {
     //UIButton properties
     func btnMultipleLines() {
         titleLabel?.numberOfLines = 0
         titleLabel?.lineBreakMode = .byWordWrapping
         titleLabel?.textAlignment = .center        
     }
}

Dans votre ViewController appelez comme ceci

button.btnMultipleLines()//This is your button
0
iOS

Rouler votre propre classe de bouton. C'est de loin la meilleure solution à long terme. UIButton et d'autres classes UIKit sont très restrictifs quant à la façon de les personnaliser.

0
unwesen

Swift 4.0

btn.titleLabel?.lineBreakMode = .byWordWrapping
btn.titleLabel?.textAlignment = .center
btn.setTitle( "Line1\nLine2", for: .normal)
0
ingconti

Ces jours-ci, si vous avez vraiment besoin que ce genre de chose soit accessible au cas par cas dans Builder Interface, vous pouvez le faire avec une simple extension comme celle-ci:

extension UIButton {
    @IBInspectable var numberOfLines: Int {
        get { return titleLabel?.numberOfLines ?? 1 }
        set { titleLabel?.numberOfLines = newValue }
    }
}

Ensuite, vous pouvez simplement définir numberOfLines en tant qu'attribut sur n'importe quelle sous-classe UIButton ou UIButton, comme s'il s'agissait d'une étiquette. Il en va de même pour toute une foule d'autres valeurs généralement inaccessibles, telles que le rayon de l'angle du calque d'une vue ou les attributs de l'ombre projetée.

0
Ash

J'ai incorporé la réponse de jessecurry dans STAButton qui fait partie de ma STAControls bibliothèque open source. Je l'utilise actuellement dans l'une des applications que je développe et cela fonctionne pour mes besoins. N'hésitez pas à ouvrir des questions sur la façon de l'améliorer ou de m'envoyer des demandes de tirage.

0
Stunner