Swift - UIButton с двумя строками текста

95

Мне было интересно, можно ли создать UIButton с двумя строками текста. Мне нужно, чтобы в каждой строке был разный размер шрифта. Первая линия будет иметь 17 пунктов, а вторая - 11 пунктов. Я пробовал возиться с помещением двух меток внутри UIButton, но я не могу заставить их оставаться в пределах кнопки.

Я пытаюсь сделать все это в конструкторе пользовательского интерфейса, а не программно.

Благодарность

Скотт
источник

Ответы:

253

Есть два вопроса.

Мне было интересно, можно ли создать UIButton с двумя строками текста

Это возможно с помощью раскадровки или программно.

Раскадровка:

Изменение «Line Mode» Перерыв для символов Wrap или Word Wrap и используйте Alt / Option + Enter ключ , чтобы ввести новую строку в поле заголовка UIButton в.

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

Программно:

override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        btnTwoLine?.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping;
}

Мне нужно, чтобы каждая строка имела другой размер шрифта 1

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

Лучший способ - использовать NSMutableAttributedString. Обратите внимание, что это может быть достигнуто только программно.

Swift 5:

@IBOutlet weak var btnTwoLine: UIButton?

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    //applying the line break mode
    textResponseButton?.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping;
    let buttonText: NSString = "hello\nthere"

    //getting the range to separate the button title strings
    let newlineRange: NSRange = buttonText.range(of: "\n")

    //getting both substrings
    var substring1 = ""
    var substring2 = ""

    if(newlineRange.location != NSNotFound) {
        substring1 = buttonText.substring(to: newlineRange.location)
        substring2 = buttonText.substring(from: newlineRange.location)
    }

    //assigning diffrent fonts to both substrings
    let font1: UIFont = UIFont(name: "Arial", size: 17.0)!
    let attributes1 = [NSMutableAttributedString.Key.font: font1]
    let attrString1 = NSMutableAttributedString(string: substring1, attributes: attributes1)

    let font2: UIFont = UIFont(name: "Arial", size: 11.0)!
    let attributes2 = [NSMutableAttributedString.Key.font: font2]
    let attrString2 = NSMutableAttributedString(string: substring2, attributes: attributes2)

    //appending both attributed strings
    attrString1.append(attrString2)

    //assigning the resultant attributed strings to the button
    textResponseButton?.setAttributedTitle(attrString1, for: [])
}

Старый Свифт

@IBOutlet weak var btnTwoLine: UIButton?

override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        //applying the line break mode
        btnTwoLine?.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping;

        var buttonText: NSString = "hello\nthere"

        //getting the range to separate the button title strings
        var newlineRange: NSRange = buttonText.rangeOfString("\n")

        //getting both substrings
        var substring1: NSString = ""
        var substring2: NSString = ""

        if(newlineRange.location != NSNotFound) {
            substring1 = buttonText.substringToIndex(newlineRange.location)
            substring2 = buttonText.substringFromIndex(newlineRange.location)
        }

        //assigning diffrent fonts to both substrings
        let font:UIFont? = UIFont(name: "Arial", size: 17.0)
        let attrString = NSMutableAttributedString(
            string: substring1 as String,
            attributes: NSDictionary(
                object: font!,
                forKey: NSFontAttributeName) as [NSObject : AnyObject])

        let font1:UIFont? = UIFont(name: "Arial", size: 11.0)
        let attrString1 = NSMutableAttributedString(
            string: substring2 as String,
            attributes: NSDictionary(
                object: font1!,
                forKey: NSFontAttributeName) as [NSObject : AnyObject])

        //appending both attributed strings
        attrString.appendAttributedString(attrString1)

        //assigning the resultant attributed strings to the button
        btnTwoLine?.setAttributedTitle(attrString, forState: UIControlState.Normal)

    }

Выход

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

Shamsudheen TK
источник
3
Работает отлично. Теперь мне интересно, есть ли способ центрировать текст в каждой строке и есть ли способ вставить больше места между двумя строками.
Скотт
3
вы можете выровнять обе строки текста по центру. напишите следующий код btnTwoLine? .titleLabel? .textAlignment = NSTextAlignment.Center или сделайте это с помощью файла раскадровки (раздел управления-> Выравнивание)
Shamsudheen TK 07
Могу я узнать, для чего нужно добавить больше строк между ними?
Shamsudheen TK
Это зависит от размера кнопки. Если кнопка большая, то две строки текста будут прямо посередине, с большим пространством сверху и снизу. Это не тот взгляд, к которому я стремился.
Скотт
вы должны применить здесь некоторые уловки :) вы можете вставить больше строк, используя несколько \ n. Я имею в виду, что "привет \ n \ n \ n здесь" даст вам три пробела. однако не забудьте изменить свой код var newlineRange: NSRange = buttonText.rangeOfString ("\ n \ n \ n")
Shamsudheen TK
22

Я искал почти ту же тему, за исключением того, что мне не нужны два разных размера шрифта. Если кто-то ищет простое решение:

    let button = UIButton()
    button.titleLabel?.numberOfLines = 0
    button.titleLabel?.lineBreakMode = .byWordWrapping
    button.setTitle("Foo\nBar", for: .normal)
    button.titleLabel?.textAlignment = .center
    button.sizeToFit()
    button.addTarget(self, action: #selector(rightBarButtonTapped), for: .allEvents)
    navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
Нико С.
источник
13

Я заметил проблему в большинстве решений, которая заключается в том, что при переводе режима разрыва строки в «Перенос символов» вторая строка будет выровнена по левому краю относительно первой строки.

Чтобы все линии были по центру. просто измените заголовок с простого на с атрибуцией, а затем вы можете сделать каждую линию центрированной

приписанный центрированный заголовок

Муса Алматри
источник
6

измените разрыв строки на перенос символов, выберите свою кнопку и в инспекторе атрибутов перейдите к разрыву строки и измените его на перенос символов

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

Сабхай Сардана
источник
6

SWIFT 3 синтаксис

let str = NSMutableAttributedString(string: "First line\nSecond Line")
str.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 17), range: NSMakeRange(0, 10))
str.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 12), range: NSMakeRange(11, 11))
button.setAttributedTitle(str, for: .normal)
Максим Князев
источник
2
не уверен, почему, но мне пришлось добавить button.titleLabel? .numberOfLines = 0
budidino 07
Сначала не работал в swift 4. Необходимо установить «разрыв строки» на «перенос слов». Спасибо, чувак :)
Каран Алангат
исходный более ранний ответ ниже: stackoverflow.com/a/30679547/5318223
Кирилл С.
5

Я исправил это, и мое решение было только в раскадровке.

Изменения:

Он добавил в Identity Inspector -> User Defined Runtime Attributes (эти KeyPaths):

  • numberOfLines = 2
  • titleLabel.textAlignment = 1

Атрибуты времени выполнения, определяемые пользователем

Я добавил это в инспекторе атрибутов:

  • разрыв строки = перенос слов

Перенос слова

А. Трехо
источник
2

Вам нужно сделать что-то из этого в коде. в IB нельзя установить 2 разных шрифта. Помимо изменения режима переноса строки на перенос символов, вам нужно что-то вроде этого, чтобы установить заголовок,

override func viewDidLoad() {
        super.viewDidLoad()
        var str = NSMutableAttributedString(string: "First line\nSecond Line")
        str.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(17), range: NSMakeRange(0, 10))
        str.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(12), range: NSMakeRange(11, 11))
        button.setAttributedTitle(str, forState: .Normal)

    }
Rdelmar
источник
1

Думаю, один из способов сделать это - использовать ярлыки. Я сделал это, и вроде работает нормально. Я мог бы создать это как UIButton, а затем выставить ярлыки, я думаю. Не знаю, есть ли в этом смысл.

    let firstLabel = UILabel()

    firstLabel.backgroundColor = UIColor.lightGrayColor()
    firstLabel.text = "Hi"
    firstLabel.textColor = UIColor.blueColor()
    firstLabel.textAlignment = NSTextAlignment.Center
    firstLabel.frame = CGRectMake(0, testButton.frame.height * 0.25, testButton.frame.width, testButton.frame.height * 0.2)
    testButton.addSubview(firstLabel)

    let secondLabel = UILabel()

    secondLabel.backgroundColor = UIColor.lightGrayColor()
    secondLabel.textColor = UIColor.blueColor()
    secondLabel.font = UIFont(name: "Arial", size: 12)
    secondLabel.text = "There"
    secondLabel.textAlignment = NSTextAlignment.Center
    secondLabel.frame = CGRectMake(0, testButton.frame.height * 0.5, testButton.frame.width, testButton.frame.height * 0.2)
    testButton.addSubview(secondLabel)
Скотт
источник
0

мой путь:

func setButtonTitle(title: String, subtitle: String, button: UIButton){
        //applying the line break mode
        button.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping;
        let title = NSMutableAttributedString(string: title, attributes: Attributes.biggestLabel)
        let subtitle = NSMutableAttributedString(string: subtitle, attributes: Attributes.label)
        let char = NSMutableAttributedString(string: "\n", attributes: Attributes.biggestLabel)
        title.append(char)
        title.append(subtitle)
        button.setAttributedTitle(title, for: .normal)
    }
Настасья
источник
0

Предлагаемые решения, к сожалению, не сработали для меня, когда я хотел иметь многолинейную кнопку внутри CollectionView. Затем коллега показал мне обходной путь, которым я хотел поделиться на случай, если у кого-то возникнет такая же проблема - надеюсь, это поможет! Создайте класс, унаследованный от UIControl, и дополните его меткой, которая затем будет вести себя аналогично кнопке.

class MultilineButton: UIControl {

    let label: UILabel = {
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.numberOfLines = 0
        $0.textAlignment = .center
        return $0
    }(UILabel())

    override init(frame: CGRect) {
        super.init(frame: frame)

        addSubview(label)

        NSLayoutConstraint.activate([
            label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
            label.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
            label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
            label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)
        ])
    }

    override var isHighlighted: Bool {
        didSet {
            backgroundColor = backgroundColor?.withAlphaComponent(isHighlighted ? 0.7 : 1.0)
            label.textColor = label.textColor.withAlphaComponent(isHighlighted ? 0.7 : 1.0)
        }
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
Mitemmetim
источник