Как добавить многострочный текст в UIButton?
-
03-07-2019 - |
Вопрос
У меня есть следующий код...
UILabel *buttonLabel = [[UILabel alloc] initWithFrame:targetButton.bounds];
buttonLabel.text = @"Long text string";
[targetButton addSubview:buttonLabel];
[targetButton bringSubviewToFront:buttonLabel];
... идея состоит в том, что я могу иметь многострочный текст для кнопки, но текст всегда скрыт фоновым изображением UIButton.Вызов журнала для отображения подпредставлений кнопки показывает, что UILabel был добавлен, но сам текст не виден.Это ошибка в UIButton или я что-то делаю не так?
Решение
Для 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 вперед,
вообще, просто сделайте эти две вещи:
- выбирать «Приписанный текст»
- во всплывающем окне «Разрыв строки» выберите "Перенос слова"
Другие советы
Выбранный ответ правильный, но если вы предпочитаете делать подобные вещи в Interface Builder, вы можете сделать это:
Если вы хотите добавить кнопку с заголовком, расположенным по центру и состоящим из нескольких строк, установите для этой кнопки настройки Интерфейсного Разработчика:
[]
Для iOS 6:
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
Как
UILineBreakModeWordWrap and UITextAlignmentCenter
устарели в iOS 6 и более поздних версиях.
Повторяя предложение Роджера Нолана, но с явным кодом, это общее решение:
button.titleLabel?.numberOfLines = 0
СВИФТ 3
button.titleLabel?.lineBreakMode = .byWordWrapping
button.titleLabel?.textAlignment = .center
button.setTitle("Button\nTitle",for: .normal)
Есть гораздо более простой способ:
someButton.lineBreakMode = UILineBreakModeWordWrap;
(Изменить для iOS 3 и более поздних версий :)
someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
Выравнивание по левому краю на iOS7 с авторазметкой:
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
Прежде всего, вы должны знать, что UIButton уже имеет внутри себя UILabel.Вы можете установить его, используя –setTitle:forState:
.
Проблема с вашим примером заключается в том, что вам нужно установить UILabel numberOfLines
для свойства, отличного от его значения по умолчанию, равного 1.Вам также следует просмотреть lineBreakMode
свойство.
В Xcode 9.3 вы можете сделать это, используя раскадровка как показано ниже,
Вам нужно установить текст заголовка кнопки в центр.
button.titleLabel?.textAlignment = .center
Вам не нужно устанавливать текст заголовка с новой строки ( ), как показано ниже,
button.setTitle("Good\nAnswer",for: .normal)
Просто установите заголовок,
button.setTitle("Good Answer",for: .normal)
Вот результат,
Те, кто использует раскадровку Xcode 4, могут нажать кнопку, и на правой панели «Утилиты» в Инспекторе атрибутов вы увидите опцию «Разрыв строки».Выберите «Перенос по словам», и все готово.
Ответы здесь расскажут вам, как программно создать многострочный заголовок кнопки.
Я просто хотел добавить, что если вы используете раскадровки, вы можете нажать [Ctrl+Enter], чтобы принудительно ввести новую строку в поле заголовка кнопки.
ХТХ
Вам необходимо добавить этот код:
buttonLabel.titleLabel.numberOfLines = 0;
Что касается идеи Брента разместить заголовок UILabel как родственное представление, мне это не кажется очень хорошей идеей.Я продолжаю думать о проблемах взаимодействия с UILabel из-за того, что его события касания не проходят через представление UIButton.
С другой стороны, когда UILabel является подпредставлением UIButton, мне вполне комфортно знать, что события касания всегда будут передаваться в суперпредставление UILabel.
Я использовал этот подход и не заметил никаких проблем, о которых сообщалось с фоновым изображением.Я добавил этот код в -titleRectForContentRect:из подкласса UIButton, но код также можно поместить в процедуру рисования суперпредставления UIButton, и в этом случае вы должны заменить все ссылки на себя переменной 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, готовый к использованию.
Если вы используете автоматическую компоновку в iOS 6, вам также может потребоваться установить preferredMaxLayoutWidth
свойство:
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.titleLabel.preferredMaxLayoutWidth = button.frame.size.width;
Он работает отлично.
Добавьте, чтобы использовать это с файлом конфигурации, например Plist, вам нужно использовать CDATA для написания многострочного заголовка, например:
<string><![CDATA[Line1
Line2]]></string>
Установка для lineBreakMode значения NSLineBreakByWordWrapping (либо в IB, либо в коде) делает метку кнопки многострочной, но не влияет на рамку кнопки.
Если кнопка имеет динамический заголовок, есть один трюк:поместите скрытый UILabel с тем же шрифтом и привяжите его высоту к высоте кнопки с помощью макета;когда установите текст на кнопку и метку, и авторазметка сделает всю работу.
Примечание
Внутренний размер высоты однострочной кнопки больше, чем высота метки, поэтому, чтобы предотвратить уменьшение высоты метки, ее вертикальный приоритет охвата контента должен быть больше, чем вертикальное сопротивление сжатию контента кнопки.
Если вы используете авторазметку.
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.titleLabel?.numberOfLines = 2
У меня была проблема с авторазметкой, после включения многострочного результата результат был такой:
Итак titleLabel
размер не влияет на размер кнопки
я добавил Constraints
на основе contentEdgeInsets
(в данном случае contentEdgeInsets был (10, 10, 10, 10)
после звонка makeMultiLineSupport()
:
надеюсь, это вам поможет (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)
])
}
}
В наши дни, если вам действительно нужно, чтобы подобные вещи были доступны в конструкторе интерфейсов в каждом конкретном случае, вы можете сделать это с помощью такого простого расширения:
extension UIButton {
@IBInspectable var numberOfLines: Int {
get { return titleLabel?.numberOfLines ?? 1 }
set { titleLabel?.numberOfLines = newValue }
}
}
Затем вы можете просто установить NumberOfLines в качестве атрибута для любого подкласса UIButton или UIButton, как если бы это была метка.То же самое касается целого ряда других обычно недоступных значений, таких как угловой радиус слоя вида или атрибуты тени, которую он отбрасывает.
Создайте свой собственный класс кнопок.Это, безусловно, лучшее решение в долгосрочной перспективе.UIButton и другие классы UIKit очень ограничены в возможностях их настройки.
self.btnError.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
self.btnError.titleLabel?.textAlignment = .center
self.btnError.setTitle("Title", for: .normal)
быстрый 4.0
btn.titleLabel?.lineBreakMode = .byWordWrapping
btn.titleLabel?.textAlignment = .center
btn.setTitle( "Line1\nLine2", for: .normal)
Я включил ответ Джессикарри в пределах STAКнопка что является частью моего STAControls библиотека с открытым исходным кодом.В настоящее время я использую его в одном из приложений, которые разрабатываю, и оно подходит для моих нужд.Не стесняйтесь открывать вопросы о том, как его улучшить, или присылайте мне запросы на включение.
В Свифт 5.0 и Хкод 10.2
Общий класс пример напиши один раз и используй все изделия
Это ваш общий класс (например, вы используете свойства всех компонентов)
import UIKit
class SharedClass: NSObject {
static let sharedInstance = SharedClass()
private override init() {
}
}
//UIButton extension
extension UIButton {
//UIButton properties
func btnMultipleLines() {
titleLabel?.numberOfLines = 0
titleLabel?.lineBreakMode = .byWordWrapping
titleLabel?.textAlignment = .center
}
}
В вашей Вьюконтроллер позвони вот так
button.btnMultipleLines()//This is your button
Хотя добавить подпредставление к элементу управления можно, нет никакой гарантии, что оно действительно будет работать, поскольку элемент управления может не ожидать его присутствия и, следовательно, вести себя плохо.Если вам это сходит с рук, просто добавьте метку в качестве родственного представления кнопки и установите ее рамку так, чтобы она перекрывала кнопку;пока он установлен поверх кнопки, никакие действия кнопки не затмят его.
Другими словами:
[button.superview addSubview:myLabel];
myLabel.center = button.center;