Jak dodać tekst wielowierszowy do przycisku UIB?

368

Mam następujący kod ...

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

... chodzi o to, że mogę mieć wieloliniowy tekst dla przycisku, ale tekst jest zawsze zasłonięty przez tło UIButton. Wywołanie rejestrowania w celu wyświetlenia widoków podrzędnych przycisku pokazuje, że dodano UILabel, ale sam tekst nie jest widoczny. Czy to błąd w UIButton, czy robię coś źle?

Owain Hunt
źródło
7
button.titleLabel?.numberOfLines = 0
ma11hew28
2
Uwaga dla tego bardzo bardzo starego QA, we współczesnym Xcode BARDZO PROSTO, WYBIERZ „ATRYBUTOWANY TEKST”, a następnie jest to banalne, wybierz „zawijanie znaków”.
Fattie
Zobacz także zaktualizowaną odpowiedź na podobne pytanie.
ToolmakerSteve
zobacz tę odpowiedź (wiele linii, szerokość dopasowania, wysokość dopasowania) tekstu przycisku stackoverflow.com/a/59211399/7523163
Hamid Reza Ansari

Odpowiedzi:

675

W systemie iOS 6 i nowszym użyj następujących poleceń, aby zezwolić na wiele linii:

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

W przypadku iOS 5 i niższych użyj następujących opcji, aby zezwolić na wiele linii:

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

2017, dla iOS9 do przodu ,

ogólnie, po prostu wykonaj te dwie rzeczy:

  1. wybierz „Tekst przypisany”
  2. w wyskakującym okienku „Podział wiersza” wybierz „Zawijanie wyrazów”
jessecurry
źródło
5
Uwaga: te przypisania są przestarzałe w iOS 6. Zaktualizowana składnia znajduje się w odpowiedzi @NiKKi poniżej.
Aaron Brager
6
Tylko żeby ludzie wiedzieli: to nie działa, jeśli używasz NSAttributString
koleś
29
Właściwie po prostu dodaj button.titleLabel.numberOfLines = 0; To sprawi, że linie będą nieograniczone. I button.titleLabel.textAlignment = NSTextAlignmentLeft; jeśli chcesz, aby tekst był wyrównany do lewej, ponieważ tytuł jest domyślnie wyśrodkowany.
RyJ
4
Szybkobutton.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
Robert
1
Dzięki @Robert za szybkie rozwiązanie. Można również użyć wnioskowania i pominąć NSLineBreakMode, tak: button.titleLabel?.lineBreakMode = .ByWordWrapping.
mjswensen,
145

Wybrana odpowiedź jest poprawna, ale jeśli wolisz zrobić coś takiego w Konstruktorze interfejsów, możesz to zrobić:

fotka

Adam Waite
źródło
58
Dziękuję mojemu 24-letniemu ja za napisanie tej odpowiedzi, od 28-letniego siebie.
Adam Waite,
5
I pozostać z jedynego Interfejs Builder konfiguracji należy ustawić titleLabel.textAlignmentprzy Numberwartości do 1w User Defined Runtime Attributedaby tekst wyśrodkowany
AnthoPak
2
Dzięki twojemu 28-letniemu ja z mojego 24-letniego ja!
Daniel Springer
59

Jeśli chcesz dodać przycisk z tytułem wyśrodkowanym wieloma liniami, ustaw dla tego interfejsu Konstruktora interfejsów:

[ tutaj]

użytkownik5440039
źródło
Czy możesz dodać tekstowy opis, jak to osiągnąć. Obraz jest świetny, ale jeśli stanie się niedostępny, twoja odpowiedź będzie bezużyteczna.
Rory McCrossan
1
@RoryMcCrossan Cześć, dodałem zdjęcie powyżej. Czy możesz to zobaczyć? Pamiętaj, że Xcode 7 nadal jest wadliwy, więc tytuł przycisku może zniknąć. Jednak po uruchomieniu aplikacji uzyskasz pożądany efekt.
user5440039,
2
Właściwie to najlepsza odpowiedź w tym wątku. Działa natychmiast i pokazuje wyśrodkowany tekst z IB. Dzięki!
RainCast
@ user5440039 Dzięki za świetną odpowiedź. Nie ma potrzeby dodawania opisu tekstowego.
Fattie,
54

Dla IOS 6:

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

Tak jak

UILineBreakModeWordWrap and UITextAlignmentCenter

są przestarzałe w IOS 6 i późniejszych.

NiKKi
źródło
Wewnątrz NSText.hw Foundationtam nie jest przestarzała dodał. Jest dostępny od wersji 6.0, ale nie jest przestarzały.
Alex Cio
W button.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping button.titleLabel?.textAlignment = NSTextAlignment.Center
krótkim
30

Aby powtórzyć sugestię Rogera Nolana, ale z wyraźnym kodem, jest to ogólne rozwiązanie:

button.titleLabel?.numberOfLines = 0
baudot
źródło
21

SWIFT 3

button.titleLabel?.lineBreakMode = .byWordWrapping
button.titleLabel?.textAlignment = .center  
button.setTitle("Button\nTitle",for: .normal)
Pan Ibrahim Hassan
źródło
13

W Xcode 9.3 możesz to zrobić za pomocą scenorysów takich jak poniżej,

wprowadź opis zdjęcia tutaj

Musisz ustawić tekst tytułu przycisku Wyrównanie do środka

button.titleLabel?.textAlignment = .center

Nie musisz ustawiać tekstu tytułu w nowej linii (\ n) jak poniżej,

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

Po prostu ustaw tytuł,

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

Oto wynik

wprowadź opis zdjęcia tutaj

Nazrul Islam
źródło
myButton.titleLabel.textAlignment = NSTextAlignmentCenterinstrukcja jest również potrzebna.
tounaobun
11

Jest o wiele łatwiejszy sposób:

someButton.lineBreakMode = UILineBreakModeWordWrap;

(Edycja dla iOS 3 i nowszych :)

someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
Valerii Hiora
źródło
4
UIButton.lineBreakMode został przestarzały w wersji 3.0, więc nie jest to już dobra opcja.
Christopher Pickslay 17.01.11
2
lineBreakMode jest przestarzałe tylko jako bezpośrednia właściwość UIButton. Zostajemy przekierowani do „Zamiast tego użyj właściwości lineBreakMode tytułu titleLabel”. Odpowiednio zredagowałem odpowiedź Valerii. To wciąż dobra opcja.
Wienke
11

Wyrównaj do lewej w iOS7 z automatycznym układem:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
neoneye
źródło
9

Miałem problem z automatycznym układem, po włączeniu wielu linii wynik był następujący: więc rozmiar nie wpływa na rozmiar przycisku , który dodałem na podstawie (w tym przypadku contentEdgeInsets to (10, 10, 10, 10 ) po zadzwonieniu : mam nadzieję, że ci to pomoże (szybkie 5.0):
wprowadź opis zdjęcia tutaj
titleLabel
ConstraintscontentEdgeInsets
makeMultiLineSupport()
wprowadź opis zdjęcia tutaj

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
źródło
Działa idealnie w trybie szybkim 5. Dodałem także moją funkcję do wyśrodkowania tekstu w przycisku. func centerTextInButton () {guard let titleLabel = titleLabel else {return} titleLabel.textAlignment = .center}
ShadeToD
Dziękuję Ci. To takie dobre rozwiązanie.
Echelon
Odkryłem, że dodanie ograniczenia nie jest konieczne, wystarczy ustawić tekst po ustawieniu lineBreakMode / textAlignment / numberOfLines. A także ustaw titleEdgeInsets dla górnej i dolnej wstawki.
Bill Chan
@BillChan niestety to nie działa we wszystkich przypadkach
Amir Khorsandi
7

Przede wszystkim należy pamiętać, że UIButton ma już w sobie UILabel. Możesz to ustawić za pomocą –setTitle:forState:.

Problem z twoim przykładem polega na tym, że musisz ustawić numberOfLineswłaściwość UILabel na wartość inną niż domyślna wartość 1. Powinieneś także przejrzeć lineBreakModewłaściwość.

Rog
źródło
Zdaję sobie sprawę z własności tytułu, ale o ile mogę stwierdzić, nie można ustawić, aby używał więcej niż jednej linii, stąd takie podejście. Jeśli wyłączę backgroundImage, pojawi się mój UILabel, co sugeruje błąd w bringSubviewToFront lub w samym UIButton.
Owain Hunt
4

Dla tych, którzy używają scenorysu Xcode 4, możesz kliknąć przycisk, a po prawej stronie okienka Narzędzia w Inspektorze atrybutów zobaczysz opcję podziału linii. Wybierz zawijanie wyrazów i powinieneś zacząć.

Jacek
źródło
4

Odpowiedzi tutaj mówią, jak programowo osiągnąć tytuł przycisku wielowierszowego.

Chciałem tylko dodać, że jeśli używasz scenariuszy, możesz wpisać [Ctrl + Enter], aby wymusić nowy wiersz w polu tytułu przycisku.

HTH

użytkownik2338871
źródło
4

Musisz dodać ten kod:

buttonLabel.titleLabel.numberOfLines = 0;
Pablo Blanco
źródło
3

Jeśli chodzi o pomysł Brenta, by umieścić tytuł UILabel jako widok rodzeństwa, nie wydaje mi się to bardzo dobrym pomysłem. Ciągle myślę w problemach z interakcją z UILabel, ponieważ zdarzenia dotykowe nie przechodzą przez widok UIButton.

Z drugiej strony, mając UILabel jako pod-widok przycisku UIBabton, czuję się całkiem komfortowo, wiedząc, że zdarzenia dotykowe zawsze będą propagowane do superwizji UILabel.

Przyjąłem to podejście i nie zauważyłem żadnego problemu zgłoszonego z backgroundImage. Dodałem ten kod do -titleRectForContentRect: podklasy UIButton, ale kod można również umieścić w procedurze rysowania superview UIButton, która w takim przypadku zastąpi wszystkie odniesienia do siebie zmienną 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;
}

Zrobiłem trochę czasu i napisałem trochę więcej na ten temat tutaj . Tam też wskazuję krótsze rozwiązanie, choć nie do końca pasuje do wszystkich scenariuszy i obejmuje hakowanie prywatnych widoków. Tam również możesz pobrać podklasę UIButton gotową do użycia.

jpedroso
źródło
3

Jeśli korzystasz z automatycznego układu na iOS 6, może być konieczne ustawienie preferredMaxLayoutWidthwłaściwości:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.titleLabel.preferredMaxLayoutWidth = button.frame.size.width;
fiolka
źródło
3

Ustawienie lineBreakMode na NSLineBreakByWordWrapping (w IB lub w kodzie) powoduje, że etykieta przycisku jest wielowierszowa, ale nie wpływa na ramkę przycisku.

Jeśli przycisk ma dynamiczny tytuł, istnieje jedna sztuczka: umieść ukryty UILabel tą samą czcionką i powiązaj jego wysokość z wysokością przycisku za pomocą układu; po ustawieniu tekstu na przycisk i etykieta oraz autolayout wszystko zadziała.

Uwaga

Wewnętrzna wielkość przycisku o jednym wierszu jest większa niż wartość etykiety, więc aby zapobiec zmniejszeniu się wysokości etykiety, jego pionowy priorytet Przytulanie zawartości musi być większy niż pionowy przycisk Odporność na kompresję treści.

Varrry
źródło
3

W Swift 5.0 i Xcode 10.2

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

W swoim ViewController zadzwoń w ten sposób

button.btnMultipleLines()//This is your button
iOS
źródło
2

Działa idealnie.

Dodaj, aby użyć tego z plikiem konfiguracyjnym, takim jak Plist, musisz użyć CDATA, aby napisać tytuł wielowarstwowy, jak poniżej:

<string><![CDATA[Line1
Line2]]></string>
makiko_fly
źródło
2

Jeśli korzystasz z automatycznego układu.

button.titleLabel?.adjustsFontSizeToFitWidth = true
button.titleLabel?.numberOfLines = 2
Sourabh Sharma
źródło
2

szybki 4.0

btn.titleLabel?.lineBreakMode = .byWordWrapping
btn.titleLabel?.textAlignment = .center
btn.setTitle( "Line1\nLine2", for: .normal)
ingconti
źródło
2

W dzisiejszych czasach, jeśli naprawdę potrzebujesz tego rodzaju rzeczy, aby być dostępnym w kreatorze interfejsów dla poszczególnych przypadków, możesz to zrobić za pomocą prostego rozszerzenia takiego jak ten:

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

Następnie możesz po prostu ustawić numberOfLines jako atrybut w dowolnej podklasie UIButton lub UIButton, tak jakby to była etykieta. To samo dotyczy całego szeregu innych zwykle niedostępnych wartości, takich jak promień narożny warstwy widoku lub atrybuty rzucanego przez niego cienia.

Popiół
źródło
2

Swift 5, dla tekstu wielowierszowego w UIButton

  let button = UIButton()
  button.titleLabel?.lineBreakMode = .byWordWrapping
  button.titleLabel?.textAlignment = .center
  button.titleLabel?.numberOfLines = 0 // for Multi line text
Manikandan
źródło
0

Rzuć własną klasą przycisków. To zdecydowanie najlepsze rozwiązanie na dłuższą metę. UIButton i inne klasy UIKit są bardzo restrykcyjne w sposobie ich dostosowywania.


źródło
0
self.btnError.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping

self.btnError.titleLabel?.textAlignment = .center

self.btnError.setTitle("Title", for: .normal)
Urvish Modi
źródło
0

I włączone odpowiedź jessecurry w zasięgu STAButton który jest częścią mojego STAControls bibliotecznych open source. Obecnie używam go w jednej z rozwijanych przeze mnie aplikacji i działa na moje potrzeby. Nie krępuj się otwierać problemów dotyczących tego, jak to poprawić lub wysyłać mi prośby o pobranie.

Szlagier
źródło
0

Aby naprawić odstępy między etykietami tytułu dla przycisku, ustaw titleEdgeInsets i inne właściwości przed 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 Przetestowałem ustawienie titleLabel? .Text Wyrównanie nie jest konieczne, a tytuł wyrównuje się .natural.

Bill Chan
źródło
-4

Chociaż dodawanie widoku podrzędnego do formantu jest w porządku, nie ma gwarancji, że faktycznie zadziała, ponieważ formant może nie oczekiwać, że tam będzie, a zatem może źle się zachowywać. Jeśli możesz to zrobić, po prostu dodaj etykietę jako widok rodzeństwa przycisku i ustaw ramkę tak, aby zachodziła na przycisk; dopóki ustawiony jest na górze przycisku, nic, co może zrobić przycisk, nie zasłoni go.

Innymi słowy:

[button.superview addSubview:myLabel];
myLabel.center = button.center;
Brent Royal-Gordon
źródło
2
Jeśli sugerujesz takie brzydkie podejście, przynajmniej nie popełniaj błędów w przykładzie kodu :). Etykieta nie powinna mieć tego samego środka co przycisk, jeśli jest widokiem podrzędnym. Użyj myLabel.frame = button.bounds; lub myLabel.center = cgPointMake (button.frame.size.with * 0.5, button.frame.size.height * 0,5)
JakubKnejzlik
1
@GrizzlyNetch Szczególnie doradzam, aby nie dodawać go jako widoku podrzędnego przycisku. addSubview:tutaj dodaje go do buttonpodglądu, dzięki czemu jest rodzeństwem przycisku, więc dopasowanie ich centrów jest prawidłowe.
Brent Royal-Gordon,
Ach, mój błąd! Masz rację, tęskniłem za „małym” faktem w superwizji: D ... przepraszam :)
JakubKnejzlik
To nie jest dokładnie to, o co pytamy, to rozwiązanie byłoby złym sposobem na zaimplementowanie pytania, ponieważ przycisk elementu ma tytuł.
Pablo Blanco
To była rozsądna rada w iPhone OS 2.0. Do tej pory są na to znacznie lepsze sposoby. : ^)
Brent Royal-Gordon