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.