Как добавить многострочный текст в UIButton? - PullRequest
349 голосов
/ 03 марта 2009

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

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

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

Ответы [ 26 ]

4 голосов
/ 01 мая 2013

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

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

НТН

4 голосов
/ 09 мая 2012

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

3 голосов
/ 09 марта 2009

Что касается идеи Брента о переводе названия 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 голосов
/ 21 февраля 2018

Вы должны добавить этот код:

buttonLabel.titleLabel.numberOfLines = 0;
2 голосов
/ 01 мая 2013

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

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.titleLabel.preferredMaxLayoutWidth = button.frame.size.width;
2 голосов
/ 11 мая 2011

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

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

<string><![CDATA[Line1
Line2]]></string>
2 голосов
/ 09 декабря 2016

Если вы используете авто-макет.

button.titleLabel?.adjustsFontSizeToFitWidth = true
button.titleLabel?.numberOfLines = 2
2 голосов
/ 31 августа 2015

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

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

Примечание

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

1 голос
/ 12 апреля 2019

У меня была проблема с автоматическим макетом, после включения многострочного результата результат был следующим:
enter image description here
поэтому размер titleLabel не влияет на размер кнопки
Я добавил Constraints на основе contentEdgeInsets (в данном случае contentEdgeInsets был (10, 10, 10, 10)
после звонка makeMultiLineSupport():
enter image description here
надеюсь, что это поможет вам (Swift 5.0):

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

}
1 голос
/ 17 ноября 2018

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

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

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

...