Как добавить многострочный текст в UIButton?


368

У меня есть следующий код ...

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

... идея в том, что я могу иметь многострочный текст для кнопки, но текст всегда скрыт backgroundImage UIButton. Запись в журнал для отображения подпредставлений кнопки показывает, что UILabel была добавлена, но сам текст не виден. Это ошибка в UIButton или я делаю что-то не так?


7
button.titleLabel?.numberOfLines = 0
ma11hew28

2
Обратите внимание, для этого очень очень старого QA, в современном Xcode ОЧЕНЬ ПРОСТО, ВЫБЕРИТЕ «ATTRIBUTED TEXT», а затем это тривиально, выберите «перенос символов».
Толстяк

Также смотрите обновленный ответ на аналогичный вопрос.
ToolmakerSteve

см. этот ответ (многострочный, ширина подгонки, высота подгонки) для текста кнопки stackoverflow.com/a/59211399/7523163
Хамид Реза Ансари

Ответы:


676

Для iOS 6 и выше используйте следующее, чтобы разрешить несколько строк:

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

Для iOS 5 и ниже используйте следующее, чтобы разрешить несколько строк:

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

2017, для iOS9 вперед ,

как правило, просто сделайте эти две вещи:

  1. выберите «Приписанный текст»
  2. во всплывающем окне «Разрыв строки» выберите «Перенос слов»

5
Обратите внимание, что эти назначения устарели в iOS 6. Обновленный синтаксис приведен ниже в ответе @NiKKi.
Аарон Брагер

6
Просто чтобы люди знали: это не работает, если вы используете NSAttributedString
Чувак

29
На самом деле, просто добавьте button.titleLabel.numberOfLines = 0; Это сделает линии неограниченными. И button.titleLabel.textAlignment = NSTextAlignmentLeft; если вы хотите выровненный по левому краю текст, поскольку заголовок по центру по умолчанию.
RyJ

4
В скором времениbutton.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
Роберт

1
Спасибо @Robert за быстрое решение. Можно также использовать вывод и опускать NSLineBreakMode, так как: button.titleLabel?.lineBreakMode = .ByWordWrapping.
mjswensen

145

Выбранный ответ правильный, но если вы предпочитаете делать такие вещи в Интерфейсном Разработчике, вы можете сделать это:

фильм


58
Спасибо моему 24-летнему Я за написание этого ответа от 28-летнего Я.
Адам Уэйт

5
И остаться с единственным Interface Builder установки, следует установить titleLabel.textAlignmentс Numberзначением , чтобы 1в , User Defined Runtime Attributedчтобы сделать текст по центру
AnthoPak

2
Благодаря вашему 28-летнему я от моего 24-летнего себя!
Даниэль Спрингер

59

Если вы хотите добавить кнопку с заголовком, центрированным несколькими строками, установите настройки Interface Builder для кнопки:

[ Вот]


Можете ли вы добавить текстовое описание того, как этого добиться. Изображение великолепно, но если оно станет недоступным, ваш ответ будет бесполезным.
Рори МакКроссан

1
@RoryMcCrossan Привет, я добавил изображение выше. Вы можете посмотреть это? Обратите внимание, что Xcode 7 все еще глючит, поэтому заголовок кнопки может исчезнуть. Однако, как только вы запустите приложение, вы получите желаемый результат.
user5440039

2
На самом деле это лучший ответ в этой теме. Работает сразу и показывает центрированный текст из IB. Спасибо!
RainCast

@ user5440039 Спасибо за отличный ответ. Нет необходимости добавлять текстовое описание.
Толстяк

54

Для IOS 6:

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

В виде

UILineBreakModeWordWrap and UITextAlignmentCenter

устарели в IOS 6 и далее ..


Внутри не NSText.hв Foundationтам нет DEPRECATED добавил. Доступно с 6.0, но не рекомендуется.
Алекс Чио,

В button.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping button.titleLabel?.textAlignment = NSTextAlignment.Center
скором времени

30

Чтобы переформулировать предложение Роджера Нолана, но с явным кодом, это общее решение:

button.titleLabel?.numberOfLines = 0


13

В Xcode 9.3 вы можете сделать это с помощью раскадровки, как показано ниже,

введите описание изображения здесь

Вам нужно установить заголовок кнопки textAlignment по центру

button.titleLabel?.textAlignment = .center

Вам не нужно устанавливать текст заголовка с новой строкой (\ n), как показано ниже,

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

Просто установите заголовок,

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

Вот результат,

введите описание изображения здесь


myButton.titleLabel.textAlignment = NSTextAlignmentCenterЗаявление также необходимо.
tounaobun

11

Есть гораздо более простой способ:

someButton.lineBreakMode = UILineBreakModeWordWrap;

(Изменить для iOS 3 и более поздних версий :)

someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;

4
UIButton.lineBreakMode устарел в 3.0, так что это уже не хороший вариант.
Кристофер Пикслей

2
lineBreakMode устарела только как прямое свойство UIButton. Нас направляют: «Вместо этого используйте свойство lineBreakMode для titleLabel». Я отредактировал ответ Валерия соответственно. Это все еще хороший вариант.
Винке

11

Выровнять по левому краю на iOS7 с помощью автоматического размещения:

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

9

У меня была проблема с авто-макета, после включения многострочный результат был так: поэтому размер не влияет на размер кнопки я добавил на основе (в этом случае contentEdgeInsets было (10, 10, 10, 10 ) после звонка : надеюсь, это поможет вам (swift 5.0):
введите описание изображения здесь
titleLabel
ConstraintscontentEdgeInsets
makeMultiLineSupport()
введите описание изображения здесь

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

}

Прекрасно работает в Swift 5. Я также добавил свою функцию для центрирования текста в кнопке. func centerTextInButton () {охранник let titleLabel = titleLabel else {return} titleLabel.textAlignment = .center}
ShadeToD

Спасибо. Это такое хорошее решение.
Эшелон

Я обнаружил, что добавление ограничений не является необходимым, просто установите текст после того, как lineBreakMode / textAlignment / numberOfLines установлены. А также установите titleEdgeInsets для верхней и нижней вставки.
Билл Чан

@BillChan, к сожалению, это работает не во всех случаях
Амир Хорсанди

7

Прежде всего, вы должны знать, что в UIButton уже есть UILabel. Вы можете установить его, используя –setTitle:forState:.

Проблема с вашим примером заключается в том, что вам нужно установить для numberOfLinesсвойства UILabel значение, отличное от значения по умолчанию, равного 1. Вы также должны просмотреть lineBreakModeсвойство.


Мне известно о свойстве title, но, насколько я могу судить, невозможно настроить его на использование более одной строки, отсюда и такой подход. Если я отключу backgroundImage, появится моя UILabel, что, по-моему, говорит об ошибке либо в файле takeSubviewToFront, либо в UIButton.
Оуайн Хант

4

Для тех, кто использует раскадровку Xcode 4, вы можете нажать на кнопку, и в правой части панели утилит в разделе Инспектора атрибутов вы увидите опцию Разрыв строки. Выберите Word Wrap, и у вас все получится.


4

Ответы здесь расскажут вам, как добиться многострочного заголовка кнопки программно.

Я просто хотел добавить, что если вы используете раскадровки, вы можете нажать [Ctrl + Enter], чтобы вызвать новую строку в поле заголовка кнопки.

НТН



3

Что касается идеи Брента о переводе названия UILabel в родную точку зрения, то мне она не кажется очень хорошей идеей. Я продолжаю думать о проблемах взаимодействия с UILabel из-за того, что его сенсорные события не проходят через точку зрения UIButton.

С другой стороны, с UILabel в качестве подпредставления UIButton, я довольно комфортно знаю, что сенсорные события всегда будут передаваться суперпредставлению UILabel.

Я использовал этот подход и не заметил никаких проблем, о которых сообщалось с backgroundImage. Я добавил этот код в -titleRectForContentRect: подкласса UIButton, но этот код также можно поместить в подпрограмму рисования суперпредставления UIButton, которая в этом случае заменяет все ссылки на self на переменную 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;
}

Я нашел время и написал немного больше об этом здесь . Там я также указываю на более короткое решение, хотя оно не совсем подходит для всех сценариев и предполагает взлом некоторых частных просмотров. Также там вы можете скачать готовый к использованию подкласс UIButton.


3

Если вы используете автоматический макет на iOS 6, вам также может потребоваться установить preferredMaxLayoutWidthсвойство:

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

3

Установка lineBreakMode в NSLineBreakByWordWrapping (либо в IB, либо в коде) делает метку кнопки многострочной, но не влияет на рамку кнопки.

Если у кнопки есть динамический заголовок, есть одна хитрость: поместите скрытую UILabel с тем же шрифтом и свяжите ее высоту с высотой кнопки с помощью макета; при установке текста на кнопку и метку и автопоставка сделает всю работу.

Запись

Внутренний размер высоты кнопки в одну строку больше, чем у метки, поэтому, чтобы предотвратить уменьшение высоты метки, ее вертикальный приоритет при перемещении содержимого должен быть больше, чем вертикальное сопротивление сжатию содержимого при нажатии кнопки.


3

В Swift 5.0 и Xcode 10.2

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

В вашем ViewController вызов, как это

button.btnMultipleLines()//This is your button

3

Swift 5, для многострочного текста в UIButton

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

2

Работает отлично.

Добавьте, чтобы использовать это с конфигурационным файлом, таким как Plist, вам нужно использовать CDATA для записи многослойного заголовка, например так:

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


2

Swift 4.0

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

2

В наши дни, если вам действительно нужно, чтобы подобные вещи были доступны в конструкторе интерфейсов в каждом конкретном случае, вы можете сделать это с помощью простого расширения, такого как:

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

Затем вы можете просто установить numberOfLines в качестве атрибута для любого подкласса UIButton или UIButton, как если бы это была метка. То же самое касается целого множества других обычно недоступных значений, таких как угловой радиус слоя вида или атрибуты отбрасываемой тени.


0

Прокрутите свой собственный класс кнопки. Это, безусловно, лучшее решение в долгосрочной перспективе. UIButton и другие классы UIKit очень ограничены в том, как вы можете их настраивать.


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

self.btnError.titleLabel?.textAlignment = .center

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

0

Я включил ответ jessecurry в STAButton, который является частью моей библиотеки с открытым исходным кодом STAControls . В настоящее время я использую его в одном из приложений, которые разрабатываю, и он работает для моих нужд. Не стесняйтесь открывать вопросы о том, как его улучшить или присылать мне запросы на извлечение.


0

Чтобы исправить расстояние между меткой заголовка и кнопкой, установите titleEdgeInsets и другие свойства перед 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 Я проверил установку titleLabel? .TextAlignment не является необходимым, и заголовок выравнивается в .natural.


-4

Хотя можно добавить подпредставление к элементу управления, нет гарантии, что оно действительно будет работать, поскольку элемент управления может не ожидать его наличия и, следовательно, может вести себя плохо. Если вам это сойдет с рук, просто добавьте метку как одноуровневое представление кнопки и установите ее рамку так, чтобы она перекрывала кнопку; пока он установлен сверху кнопки, ничто, что может сделать кнопка, не затеняет его.

Другими словами:

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

2
Пожалуйста, если вы предлагаете такой уродливый подход, по крайней мере, не допускайте ошибок в своем примере кода :). У ярлыка не должно быть того же центра, что и у кнопки, если это подпредставление. Используйте myLabel.frame = button.bounds; или myLabel.center = cgPointMake (button.frame.size.with * 0,5, button.frame.size.height * 0,5)
JakubKnejzlik

1
@GrizzlyNetch Я специально советую не добавлять его в качестве подпредставления кнопки. addSubview:здесь он добавляется в buttonсуперпредставление, таким образом делая его родным по отношению к кнопке, поэтому соответствие их центров является правильным.
Брент Роял-Гордон

Ах, моя ошибка! Вы правы, я пропустил "маленький" факт, что это в суперпредставлении: D ... извините :)
JakubKnejzlik

То, что это не совсем то, о чем спрашивают, это решение было бы плохим способом реализовать вопрос, так как кнопка элемента имеет заголовок.
Пабло Бланко

Это был разумный совет в iPhone OS 2.0. Есть гораздо лучшие способы сделать это сейчас. : ^)
Брент Роял-Гордон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.