Como você adiciona texto de várias linhas a um UIButton?

368

Eu tenho o seguinte código...

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

... a ideia é que eu posso ter texto com várias linhas para o botão, mas o texto é sempre obscurecido pela backgroundImage do UIButton. Uma chamada de log para mostrar as subvisões do botão mostra que o UILabel foi adicionado, mas o texto em si não pode ser visto. Isso é um bug no UIButton ou estou fazendo algo errado?

Owain Hunt
fonte
7
button.titleLabel?.numberOfLines = 0
Ma11hew28
2
Observe esse controle de qualidade muito antigo, no Xcode moderno MUITO SIMPLESMENTE, ESCOLHA "TEXTO ATRIBUÍDO" e, em seguida, é trivial, selecione "quebra de caracteres".
Fattie
Consulte também a resposta atualizada para uma pergunta semelhante.
Home
veja esta resposta (multi linha, largura de ajuste, ajuste de altura) para o texto do botão stackoverflow.com/a/59211399/7523163
Hamid Reza Ansari

Respostas:

676

Para iOS 6 e superior, use o seguinte para permitir várias linhas:

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

Para iOS 5 e abaixo, use o seguinte para permitir várias linhas:

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

2017, para iOS9 em diante ,

Geralmente, basta fazer estas duas coisas:

  1. escolha "Texto atribuído"
  2. no pop-up "Quebra de linha", selecione " Quebra de linha "
jessecurry
fonte
5
Observe que essas atribuições foram descontinuadas no iOS 6. Veja a resposta abaixo de @NiKKi para obter a sintaxe atualizada.
Aaron Brager
6
Só assim as pessoas sabem: isso não funciona se você estiver usando NSAttributedString
O cara
29
Na verdade, basta adicionar button.titleLabel.numberOfLines = 0; Isso tornará as linhas ilimitadas. E button.titleLabel.textAlignment = NSTextAlignmentLeft; se você quiser um texto justificado à esquerda, pois o título é centralizado por padrão.
RyJ 21/08/14
4
Em rápidabutton.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
Robert
11
Obrigado @Robert pela solução rápida. Também é possível usar inferência e omitir o NSLineBreakMode, assim: button.titleLabel?.lineBreakMode = .ByWordWrapping.
precisa saber é o seguinte
145

A resposta selecionada está correta, mas se você preferir fazer isso no Interface Builder, pode fazer o seguinte:

foto

Adam Waite
fonte
58
Agradeço ao meu eu de 24 anos por escrever esta resposta, do eu de 28 anos.
Adam Waite
5
E para ficar com a única configuração Interface Builder, deve-se definir titleLabel.textAlignmentcom Numbervalor de 1no User Defined Runtime Attributedpara tornar o texto centrado
AnthoPak
2
Graças ao seu eu de 28 anos, do meu eu de 24 anos!
Daniel Springer
59

Se você deseja adicionar um botão com o título centralizado em várias linhas, defina as configurações do Interface Builder para o botão:

[ aqui]

user5440039
fonte
Você pode adicionar uma descrição textual de como conseguir isso. Uma imagem é ótima, mas, se ficar indisponível, sua resposta será inútil.
Rory McCrossan
11
@RoryMcCrossan Olá, adicionei uma imagem acima. Você pode vê-lo? Observe que o Xcode 7 ainda está com erros, portanto o título do botão pode desaparecer. No entanto, depois de executar o aplicativo, você obterá o resultado desejado.
user5440039
2
Esta é a melhor resposta neste tópico, na verdade. Trabalha imediatamente e mostra o texto centralizado do IB. Obrigado!
RainCast
@ user5440039 Obrigado pela ótima resposta. Não há necessidade de adicionar uma descrição textual.
Fattie
54

Para o IOS 6:

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

Como

UILineBreakModeWordWrap and UITextAlignmentCenter

são preteridos no IOS 6 em diante ..

NiKKi
fonte
No interior NSText.h, Foundationnão há itens obsoletos adicionados. Está disponível a partir do 6.0, mas não obsoleto.
Alex Cio #
Em swift: button.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping button.titleLabel?.textAlignment = NSTextAlignment.Center
jcity 02/12/2015
30

Para reafirmar a sugestão de Roger Nolan, mas com código explícito, esta é a solução geral:

button.titleLabel?.numberOfLines = 0
baudot
fonte
21

SWIFT 3

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

No Xcode 9.3, você pode fazer isso usando o storyboard como abaixo,

insira a descrição da imagem aqui

Você precisa definir o texto do título do botão

button.titleLabel?.textAlignment = .center

Você não precisa definir o texto do título com a nova linha (\ n), como abaixo,

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

Basta definir o título,

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

Aqui está o resultado,

insira a descrição da imagem aqui

Nazrul Islam
fonte
myButton.titleLabel.textAlignment = NSTextAlignmentCenterdeclaração também é necessária.
precisa saber é o seguinte
11

Existe uma maneira muito mais fácil:

someButton.lineBreakMode = UILineBreakModeWordWrap;

(Editar para iOS 3 e posterior :)

someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
Valerii Hiora
fonte
4
O UIButton.lineBreakMode foi descontinuado no 3.0, portanto, não é mais uma boa opção.
precisa saber é o seguinte
2
lineBreakMode foi preterido apenas como uma propriedade direta de UIButton. Somos direcionados a "Use a propriedade lineBreakMode do titleLabel". Eu editei a resposta de Valerii de acordo. Ainda é uma boa opção.
Wienke
11

Alinhar à esquerda no iOS7 com o layout automático:

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

Eu tive um problema com o layout automático, depois de ativar várias linhas, o resultado foi o seguinte: portanto, o tamanho não afeta o tamanho do botão que eu adicionei com base (nesse caso, contentEdgeInsets era (10, 10, 10, 10 ) após ligar : espero que ajude você (swift 5.0):
insira a descrição da imagem aqui
titleLabel
ConstraintscontentEdgeInsets
makeMultiLineSupport()
insira a descrição da imagem aqui

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

}
Amir Khorsandi
fonte
Funciona perfeitamente no 5. rápido. Também adicionei minha função para centralizar o texto no botão. func centerTextInButton () {guarda deixe titleLabel = titleLabel else {retorno} titleLabel.textAlignment = .center}
ShadeToD
Obrigado. Essa é uma solução tão boa.
Echelon
Eu achei que adicionar restrição não é necessário, basta definir o texto após definir lineBreakMode / textAlignment / numberOfLines. E também defina titleEdgeInsets para inserção superior e inferior.
Bill Chan
@BillChan infelizmente isso não funciona em todos os casos
Amir Khorsandi
7

Primeiro de tudo, você deve estar ciente de que o UIButton já possui um UILabel dentro dele. Você pode configurá-lo usando –setTitle:forState:.

O problema com o seu exemplo é que você precisa definir a numberOfLinespropriedade do UILabel para algo diferente do valor padrão de 1. Você também deve revisar a lineBreakModepropriedade.

Rog
fonte
Estou ciente da propriedade title, mas, tanto quanto posso dizer, é impossível configurá-la para usar mais de uma linha, portanto, essa abordagem. Se eu desativar o backgroundImage, meu UILabel aparecerá, o que para mim sugere um bug no bringSubviewToFront ou no próprio UIButton.
Owain Hunt
4

Para aqueles que estão usando o storyboard do Xcode 4, clique no botão e, no painel Utilitários do lado direito, em Inspetor de Atributos, você verá uma opção para Quebra de Linha. Escolha Quebra de linha, e você deve estar pronto.

Jack
fonte
4

As respostas aqui mostram como obter o título do botão com várias linhas programaticamente.

Eu só queria acrescentar que, se você estiver usando storyboards, poderá digitar [Ctrl + Enter] para forçar uma nova linha no campo de título de um botão.

HTH

user2338871
fonte
4

Você precisa adicionar este código:

buttonLabel.titleLabel.numberOfLines = 0;
Pablo Blanco
fonte
3

Quanto à idéia de Brent de colocar o título UILabel como visão de irmão, não me parece uma idéia muito boa. Eu continuo pensando em problemas de interação com o UILabel devido a seus eventos de toque que não passam pela visão do UIButton.

Por outro lado, com um UILabel como sub-visualização do UIButton, estou bastante confortável sabendo que os eventos de toque sempre serão propagados para a super-visão do UILabel.

Eu segui essa abordagem e não percebi nenhum dos problemas relatados com backgroundImage. Eu adicionei esse código na -titleRectForContentRect: de uma subclasse UIButton, mas o código também pode ser colocado na rotina de desenho da superview UIButton, que nesse caso você deve substituir todas as referências a self pela variável 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;
}

Demorei um pouco e escrevi um pouco mais sobre isso aqui . Lá, também aponto uma solução mais curta, embora ela não se encaixe perfeitamente em todos os cenários e envolva algumas visualizações privadas de hackers. Também é possível baixar uma subclasse UIButton pronta para ser usada.

jpedroso
fonte
3

Se você usa o layout automático no iOS 6, também pode ser necessário definir a preferredMaxLayoutWidthpropriedade:

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

Definir lineBreakMode como NSLineBreakByWordWrapping (no IB ou no código) torna o rótulo do botão multilinha, mas não afeta o quadro do botão.

Se o botão tiver título dinâmico, existe um truque: coloque o UILabel oculto com a mesma fonte e amarre sua altura à altura do botão com layout; quando definir o texto como botão e rotular e o layout automático fará todo o trabalho.

Nota

A altura do tamanho intrínseco do botão de uma linha é maior que a da etiqueta; portanto, para evitar que a altura da etiqueta diminua, é vertical A Prioridade de abraço de conteúdo deve ser maior que a resistência vertical à compressão de conteúdo do botão.

Varrry
fonte
3

No Swift 5.0 e no Xcode 10.2

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

Na sua chamada ViewController como esta

button.btnMultipleLines()//This is your button
iOS
fonte
3

Swift 5, para texto de várias linhas no UIButton

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

Funciona perfeitamente.

Adicione para usar isso com o arquivo de configuração como o Plist, você precisa usar o CDATA para escrever o título com várias linhas, assim:

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

Se você usa o layout automático.

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

swift 4.0

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

Hoje em dia, se você realmente precisa desse tipo de coisa para ser acessível no construtor de interface caso a caso, pode fazê-lo com uma extensão simples como esta:

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

Em seguida, você pode simplesmente definir numberOfLines como um atributo em qualquer subclasse UIButton ou UIButton como se fosse um rótulo. O mesmo vale para uma série de outros valores geralmente inacessíveis, como o raio do canto da camada de uma vista ou os atributos da sombra que ela lança.

Cinza
fonte
0

Role sua própria classe de botão. É de longe a melhor solução a longo prazo. O UIButton e outras classes do UIKit são muito restritivas na maneira como você pode personalizá-las.


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

self.btnError.titleLabel?.textAlignment = .center

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

Incorporei a resposta de jessecurry no STAButton, que faz parte da minha biblioteca de código aberto STAControls . Atualmente, eu o uso em um dos aplicativos que estou desenvolvendo e funciona para minhas necessidades. Fique à vontade para abrir questões sobre como aprimorá-lo ou me enviar solicitações pull.

Stunner
fonte
0

Para corrigir o espaçamento do rótulo do título no botão, defina titleEdgeInsets e outras propriedades antes de 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 Eu testei a configuração titleLabel? .TextAlignment não é necessário e o título se alinha .natural.

Bill Chan
fonte
-4

Embora seja bom adicionar uma subvisão a um controle, não há garantia de que realmente funcione, porque o controle pode não esperar que esteja lá e, portanto, se comportar mal. Se você conseguir se safar, basta adicionar o rótulo como uma visão irmão do botão e definir seu quadro para que ele se sobreponha ao botão; desde que esteja definido para aparecer na parte superior do botão, nada que ele possa fazer o ocultará.

Em outras palavras:

[button.superview addSubview:myLabel];
myLabel.center = button.center;
Brent Royal-Gordon
fonte
2
Por favor, se você sugerir esse tipo de abordagem feia, pelo menos não cometa erros no seu exemplo de código :). O rótulo não deve ter o mesmo centro que o botão se for uma subvisão. Use myLabel.frame = button.bounds; ou myLabel.center = cgPointMake (button.frame.size.with * 0.5, button.frame.size.height * 0.5)
#
11
@GrizzlyNetch Estou aconselhando especificamente não adicioná-lo como uma sub-visualização do botão. addSubview:aqui o adiciona à buttonsuper visão de, tornando-o irmão do botão, para que a correspondência entre os centros esteja correta.
Brent Royal-Gordon
Ah, meu erro! Você está certo, eu perdi o fato de "pequeno" é no superview: D ... desculpe :)
JakubKnejzlik
Como não é exatamente o que é solicitado, essa solução seria uma maneira ruim de implementar a pergunta, já que o botão do elemento possui um título.
Pablo Blanco
Este foi um conselho razoável no iPhone OS 2.0. Existem maneiras muito melhores de fazê-lo agora. : ^)
Brent Royal-Gordon