Come si aggiunge il testo su più righe a un UIButton?


368

Ho il codice seguente...

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

... l'idea è che posso avere un testo su più righe per il pulsante, ma il testo è sempre oscurato dallo sfondoImmagine di UIButton. Una chiamata di registrazione per mostrare le visualizzazioni secondarie del pulsante mostra che UILabel è stato aggiunto, ma il testo stesso non può essere visto. È un bug in UIButton o sto facendo qualcosa di sbagliato?


7
button.titleLabel?.numberOfLines = 0
ma11hew28,

2
Nota per questo QA molto antico, nel moderno Xcode MOLTO SEMPLICE, SCEGLI "TESTO ATTRIBUITO" e poi è banale, seleziona "A capo automatico".
Fattie,

Vedi anche la risposta aggiornata a una domanda simile.
ToolmakerSteve

vedi questa risposta (multi linea, larghezza adattamento, altezza adattamento) per il testo del pulsante stackoverflow.com/a/59211399/7523163
Hamid Reza Ansari

Risposte:


676

Per iOS 6 e versioni successive, utilizzare quanto segue per consentire più linee:

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

Per iOS 5 e versioni successive utilizzare quanto segue per consentire più linee:

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

2017, per iOS9 forward ,

in genere, fai solo queste due cose:

  1. scegli "Testo attribuito"
  2. nel popup "Interruzione di riga" selezionare "A capo automatico"

5
Si noti che questi compiti sono obsoleti in iOS 6. Vedere la risposta di seguito da @NiKKi per la sintassi aggiornata.
Aaron Brager

6
Solo così la gente lo sa: questo non funziona se stai usando NSAttributedString
The dude

29
In realtà, basta aggiungere button.titleLabel.numberOfLines = 0; Ciò renderà le linee illimitate. E button.titleLabel.textAlignment = NSTextAlignmentLeft; se si desidera un testo giustificato a sinistra poiché il titolo è centrato per impostazione predefinita.
RyJ,

4
In breve tempobutton.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
Robert,

1
Grazie @Robert per la rapida soluzione. È inoltre possibile utilizzare l'inferenza e omettere la NSLineBreakMode, in questo modo: button.titleLabel?.lineBreakMode = .ByWordWrapping.
mjswensen,

145

La risposta selezionata è corretta ma se preferisci fare questo genere di cose in Interface Builder puoi farlo:

pic


58
Grazie a me stesso di 24 anni per aver scritto questa risposta, da me stesso di 28 anni.
Adam Waite,

5
E per rimanere solo con l' titleLabel.textAlignmentNumber1User Defined Runtime Attributed
Installazione

2
Grazie a te stesso di 28 anni dal mio io di 24 anni!
Daniel Springer,

59

Se vuoi aggiungere un pulsante con il titolo centrato su più righe, imposta le impostazioni di Interface Builder per il pulsante:

[ Qui]


Puoi aggiungere una descrizione testuale su come raggiungere questo obiettivo. Un'immagine è fantastica, ma se diventa non disponibile la tua risposta sarà inutile.
Rory McCrossan,

1
@RoryMcCrossan Ciao, ho aggiunto un'immagine sopra. Puoi vederlo? Nota: Xcode 7 è ancora difettoso, quindi il titolo del pulsante potrebbe scomparire. Tuttavia, una volta eseguita l'app, otterrai il risultato desiderato.
user5440039,

2
Questa è la migliore risposta in questo thread, in realtà. Funziona immediatamente e mostra il testo centrato da IB. Grazie!
RainCast,

@ user5440039 Grazie per l'ottima risposta. Non è necessario aggiungere una descrizione testuale.
Fattie,

54

Per IOS 6:

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

Come

UILineBreakModeWordWrap and UITextAlignmentCenter

sono obsoleti in IOS 6 in poi.


All'interno NSText.hdel Foundationnon c'è deprecato aggiunto. È disponibile dalla 6.0 ma non obsoleto.
Alex Cio,

In button.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping button.titleLabel?.textAlignment = NSTextAlignment.Center
breve tempo

30

Per riaffermare il suggerimento di Roger Nolan, ma con un codice esplicito, questa è la soluzione generale:

button.titleLabel?.numberOfLines = 0

21

SWIFT 3

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

13

In Xcode 9.3 puoi farlo utilizzando lo storyboard come di seguito,

inserisci qui la descrizione dell'immagine

È necessario impostare il testo del titolo del pulsante Allineamento al centro

button.titleLabel?.textAlignment = .center

Non è necessario impostare il testo del titolo con una nuova riga (\ n) come di seguito,

button.setTitle("Good\nAnswer",for: .normal)

Basta impostare il titolo,

button.setTitle("Good Answer",for: .normal)

Ecco il risultato,

inserisci qui la descrizione dell'immagine


myButton.titleLabel.textAlignment = NSTextAlignmentCenterdichiarazione è anche necessaria.
tounaobun,

11

C'è un modo molto più semplice:

someButton.lineBreakMode = UILineBreakModeWordWrap;

(Modifica per iOS 3 e versioni successive :)

someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;

4
UIButton.lineBreakMode è stato deprecato in 3.0, quindi non è più una buona opzione.
Christopher Pickslay,

2
lineBreakMode è deprecato solo come proprietà diretta di UIButton. Siamo indirizzati a "Utilizzare invece la proprietà lineBreakMode di titleLabel". Ho modificato la risposta di Valerii di conseguenza. È ancora una buona opzione.
Wienke,

11

Allineamento a sinistra su iOS7 con autolayout:

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

9

Ho avuto un problema con il layout automatico, dopo aver abilitato la multilinea il risultato è stato questo: quindi la dimensione non influisce sulla dimensione del pulsante che ho aggiunto in base (in questo caso contentEdgeInsets era (10, 10, 10, 10 ) dopo aver chiamato : spero che ti aiuti (rapido 5.0):
inserisci qui la descrizione dell'immagine
titleLabel
ConstraintscontentEdgeInsets
makeMultiLineSupport()
inserisci qui la descrizione dell'immagine

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

}

Funziona perfettamente in rapido 5. Ho anche aggiunto la mia funzione per centrare il testo nel pulsante. func centerTextInButton () {guard let titleLabel = titleLabel else {return} titleLabel.textAlignment = .center}
ShadeToD

Grazie. Questa è una buona soluzione.
Echelon,

Ho trovato che non è necessario aggiungere un vincolo, basta impostare il testo dopo aver impostato lineBreakMode / textAlignment / numberOfLines. E imposta anche titleEdgeInsets per l'inserzione superiore e inferiore.
Bill Chan,

@BillChan purtroppo non funziona in tutti i casi
Amir Khorsandi

7

Prima di tutto, dovresti essere consapevole che UIButton ha già una UILabel al suo interno. Puoi impostarlo usando –setTitle:forState:.

Il problema con il tuo esempio è che devi impostare la numberOfLinesproprietà di UILabel su qualcosa di diverso dal suo valore predefinito di 1. Dovresti anche rivedere la lineBreakModeproprietà.


Sono a conoscenza della proprietà del titolo, ma per quanto ne so è impossibile impostarlo per utilizzare più di una riga, quindi questo approccio. Se disabilito backgroundImage, viene visualizzato il mio UILabel, che a mio avviso suggerisce un bug in bringSubviewToFront o UIButton stesso.
Owain Hunt,

4

Per coloro che utilizzano lo storyboard di Xcode 4, è possibile fare clic sul pulsante e sul pannello Utilità sul lato destro in Impostazioni attributi, vedrai un'opzione per Interruzione di riga. Scegli Word Wrap e dovresti essere bravo ad andare.


4

Le risposte qui ti spiegano come ottenere il titolo del pulsante multilinea a livello di codice.

Volevo solo aggiungere che se si utilizzano gli storyboard, è possibile digitare [Ctrl + Invio] per forzare una nuova riga sul campo del titolo di un pulsante.

HTH


4

Devi aggiungere questo codice:

buttonLabel.titleLabel.numberOfLines = 0;

3

Per quanto riguarda l'idea di Brent di mettere il titolo UILabel come una visione di pari livello, non mi sembra un'ottima idea. Continuo a pensare a problemi di interazione con UILabel a causa dei suoi eventi tattili che non riescono a superare la vista di UIButton.

D'altra parte, con una UILabel come sottoview della UIButton, sono abbastanza a mio agio sapendo che gli eventi touch saranno sempre propagati alla superview della UILabel.

Ho adottato questo approccio e non ho notato nessuno dei problemi segnalati con backgroundImage. Ho aggiunto questo codice nella -titleRectForContentRect: di una sottoclasse UIButton ma il codice può anche essere inserito nella routine di disegno della superview UIButton, che in tal caso sostituirai tutti i riferimenti a sé con la variabile 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;
}

Mi sono preso il tempo e ho scritto un po 'di più su questo qui . Lì, suggerisco anche una soluzione più breve, anche se non si adatta perfettamente a tutti gli scenari e coinvolge alcune visualizzazioni private. Inoltre, è possibile scaricare una sottoclasse UIButton pronta per essere utilizzata.


3

Se si utilizza il layout automatico su iOS 6, potrebbe essere necessario impostare anche la preferredMaxLayoutWidthproprietà:

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

3

L'impostazione di lineBreakMode su NSLineBreakByWordWrapping (in IB o in codice) rende l'etichetta del pulsante multilinea, ma non influisce sulla cornice del pulsante.

Se il pulsante ha un titolo dinamico, c'è un trucco: mettere UILabel nascosto con lo stesso carattere e legare l'altezza all'altezza del pulsante con il layout; quando si imposta il testo su pulsante ed etichetta e il completamento automatico farà tutto il lavoro.

Nota

L'altezza delle dimensioni intrinseche del pulsante di una riga è maggiore di quella dell'etichetta, quindi per evitare che l'altezza dell'etichetta si riduca è verticale La priorità di abbraccio al contenuto deve essere maggiore della resistenza di compressione del contenuto verticale del pulsante.


3

In Swift 5.0 e Xcode 10.2

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

Nel tuo ViewController chiama così

button.btnMultipleLines()//This is your button

3

Swift 5, per testo su più righe in UIButton

  let button = UIButton()
  button.titleLabel?.lineBreakMode = .byWordWrapping
  button.titleLabel?.textAlignment = .center
  button.titleLabel?.numberOfLines = 0 // for Multi line text

2

Funziona perfettamente.

Aggiungi per usarlo con il file di configurazione come Plist, devi usare CDATA per scrivere il titolo multilinea, in questo modo:

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

2

Se si utilizza il layout automatico.

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

2

rapido 4.0

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

2

In questi giorni, se hai davvero bisogno di questo genere di cose per essere accessibile nel builder di interfacce caso per caso, puoi farlo con una semplice estensione come questa:

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

Quindi puoi semplicemente impostare numberOfLines come attributo su qualsiasi sottoclasse UIButton o UIButton come se fosse un'etichetta. Lo stesso vale per tutta una serie di altri valori solitamente inaccessibili, come il raggio d'angolo del livello di una vista o gli attributi dell'ombra che esso proietta.


0

Crea la tua classe di pulsanti. È di gran lunga la migliore soluzione a lungo termine. UIButton e altre classi UIKit sono molto restrittive nel modo in cui è possibile personalizzarle.


0
self.btnError.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping

self.btnError.titleLabel?.textAlignment = .center

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

0

Ho incorporato la risposta di jessecurry all'interno di STAButton che fa parte della mia libreria open source STAControls . Attualmente lo uso all'interno di una delle app che sto sviluppando e funziona per le mie esigenze. Sentiti libero di aprire problemi su come migliorarlo o inviarmi richieste pull.


0

Per correggere la spaziatura dell'etichetta del titolo sul pulsante, imposta titleEdgeInsets e altre proprietà prima di setTitle:

    let set = UIButton()
    sut.titleLabel?.lineBreakMode = .byWordWrapping
    sut.titleLabel?.numberOfLines = 0
    sut.titleEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 20, right: 20)
    sut.setTitle("Dummy button with long long long long long long long long title", for: .normal)

PS Ho provato a impostare titleLabel? .TextAlignment non è necessario e il titolo si allinea .natural.


-4

Anche se va bene aggiungere una sottoview a un controllo, non c'è alcuna garanzia che funzioni effettivamente, perché il controllo potrebbe non aspettarsi che sia lì e potrebbe quindi comportarsi male. Se riesci a cavartela, aggiungi l'etichetta come una vista fratello del pulsante e imposta la sua cornice in modo che si sovrapponga al pulsante; fintanto che è impostato per apparire in cima al pulsante, nulla che il pulsante possa fare lo oscurerà.

In altre parole:

[button.superview addSubview:myLabel];
myLabel.center = button.center;

2
Per favore, se suggerisci questo tipo di brutto approccio almeno non commettere errori nell'esempio di codice :). L'etichetta non dovrebbe avere lo stesso centro del pulsante se è una vista secondaria. Usa myLabel.frame = button.bounds; o myLabel.center = cgPointMake (button.frame.size.with * 0.5, button.frame.size.height * 0.5)
JakubKnejzlik

1
@GrizzlyNetch Consiglio in particolare di non aggiungerlo come sottoview del pulsante. addSubview:qui lo aggiunge alla buttonsuperview, rendendolo così fratello del pulsante, quindi la corrispondenza dei loro centri è corretta.
Brent Royal-Gordon,

Ah, errore mio! Hai ragione, ho perso il fatto "piccolo" che è nella superview: D ... scusa :)
JakubKnejzlik

Che non sia esattamente ciò che viene chiesto, questa soluzione sarebbe un cattivo modo di implementare la domanda poiché il pulsante dell'elemento ha un titolo.
Pablo Blanco,

Questo era un consiglio ragionevole in iPhone OS 2.0. Ormai ci sono molti modi migliori per farlo. : ^)
Brent Royal-Gordon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.