Как изменить расстояние между буквами UIButton в Swift?

Я нашел, как установить интервал между буквами в UILabel (здесь) но этот метод не работает для UIButtons. кто нибудь знает как это сделать?

Вот код, который я использую

    let buttonString = agreementButton.attributedTitleForState(.Normal) as! NSMutableAttributedString
    buttonString.addAttribute(NSKernAttributeName, value: 1.0, range: NSMakeRange(0, buttonString.length))
    agreementButton.setAttributedTitle(buttonString, forState: .Normal)

Выдает ошибку: 'NSConcreteAttributedString' (0x19e508660) to 'NSMutableAttributedString' (0x19e506a40).


person A.Solodky    schedule 02.12.2015    source источник
comment
Где именно проблема? Пожалуйста, опубликуйте код, который у вас не работает.   -  person Laurent Rivard    schedule 02.12.2015
comment
Обновлено, чтобы вы могли увидеть неработающий код.   -  person A.Solodky    schedule 02.12.2015


Ответы (9)


  1. Сделайте NSAttributedString как в вопросе, который вы связали
  2. Позвоните setAttributedTitle(_ ,forState:) на свой UIButton

Попробуйте это (не проверено):

let title = agreementButton.titleForState(.Normal)
let attributedTitle = NSAttributedString(string: title, attributes: [NSKernAttributeName: 1.0])
agreementButton.setAttributedTitle(attributedTitle, forState: .Normal)
person Code Different    schedule 02.12.2015
comment
Виноват. Должно было быть просто setAttributedTitle. Отредактировано - person Code Different; 02.12.2015

Свифт 3.0

extension UIButton{
   func addTextSpacing(spacing: CGFloat){
       let attributedString = NSMutableAttributedString(string: (self.titleLabel?.text!)!)
       attributedString.addAttribute(NSKernAttributeName, value: spacing, range: NSRange(location: 0, length: (self.titleLabel?.text!.characters.count)!))
       self.setAttributedTitle(attributedString, for: .normal)
   }
}
btnRegister.addTextSpacing(spacing: 4.5)

extension UILabel{
    func addTextSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.text!)
        attributedString.addAttribute(NSKernAttributeName, value: spacing, range: NSRange(location: 0, length: self.text!.characters.count))
        self.attributedText = attributedString
    }
}
lblOne.addTextSpacing(spacing: 4.5)

extension UITextField{
    func addPlaceholderSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.placeholder!)
        attributedString.addAttribute(NSKernAttributeName, value: spacing, range: NSRange(location: 0, length: self.placeholder!.characters.count))
        self.attributedPlaceholder = attributedString
    }
}
txtUserName.addPlaceholderSpacing(spacing: 4.5)

extension UINavigationItem{
    func addSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.title!)
        attributedString.addAttribute(NSKernAttributeName, value: spacing, range: NSRange(location: 0, length: self.title!.characters.count))
        let label = UILabel()
        label.textColor = UIColor.black
        label.font = UIFont.systemFont(ofSize: 15, weight: UIFontWeightBold)
        label.attributedText = attributedString
        label.sizeToFit()
        self.titleView = label
    }
}
navigationItem.addSpacing(spacing: 2.5)
person jaya raj    schedule 16.11.2016

Свифт 4

extension UIButton{

    func addTextSpacing(_ letterSpacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: (self.titleLabel?.text!)!)
        attributedString.addAttribute(NSAttributedString.Key.kern, value: letterSpacing, range: NSRange(location: 0, length: (self.titleLabel?.text!.count)!))
        self.setAttributedTitle(attributedString, for: .normal)
    }

}

// Usage: button.addTextSpacing(5.0)
person Max    schedule 02.09.2018
comment
Работает отлично! NSAttributedStringKey теперь должен быть NSAttributedString.Key. - person J A S K I E R; 11.09.2018

Не полный ответ, а GOTCHA и FIX.

GOTCHA: применение межсимвольного интервала также добавляет пробел в КОНЕЦ текста. Эта ошибка означает, что выровненный по центру текст будет отображаться неправильно.

ИСПРАВЛЕНИЕ: при создании диапазона для атрибутированного текста вычтите 1 из значения text.count (таким образом игнорируя последний символ в строке для целей пробела).

например неправильное центрирование из-за лишнего места:

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

исправлено:

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

[отредактировано]

В связи с этим, если вы используете EdgeInsets для наложения отступов вокруг текста, ваш подкласс UIButton должен будет переопределить intrinsicContentsSize:

override open var intrinsicContentSize: CGSize {
    let size = super.intrinsicContentSize
    let insets = self.titleEdgeInsets
    let width = size.width + insets.left + insets.right
    let height = size.height + insets.top + insets.bottom
    return CGSize(width: width, height: height)
}
person Womble    schedule 02.05.2019

Расширение Swift 5 находится здесь.

extension UIButton {
    @IBInspectable
    var letterSpacing: CGFloat {
        set {
            let attributedString: NSMutableAttributedString
            if let currentAttrString = attributedTitle(for: .normal) {
                attributedString = NSMutableAttributedString(attributedString: currentAttrString)
            }
            else {
                attributedString = NSMutableAttributedString(string: self.title(for: .normal) ?? "")
                setTitle(.none, for: .normal)
            }

            attributedString.addAttribute(NSAttributedString.Key.kern, value: newValue, range: NSRange(location: 0, length: attributedString.length))
            setAttributedTitle(attributedString, for: .normal)
        }
        get {
            if let currentLetterSpace = attributedTitle(for: .normal)?.attribute(NSAttributedString.Key.kern, at: 0, effectiveRange: .none) as? CGFloat {
                return currentLetterSpace
            }
            else {
                return 0
            }
        }
    }
}

Использование: Вы можете установить пространство для букв на раскадровке или по коду.

button.letterSpacing = 2.0
person Li Jin    schedule 23.09.2020

Решение из Code Different не учитывает настройки цвета текста. Также можно переопределить класс UIButton, чтобы параметр интервала был доступен даже в раскадровке. Вот обновленное решение Swift 3:

Свифт 3

class UIButtonWithSpacing : UIButton
{
    override func setTitle(_ title: String?, for state: UIControlState)
    {
        if let title = title, spacing != 0
        {
            let color = super.titleColor(for: state) ?? UIColor.black
            let attributedTitle = NSAttributedString(
                string: title,
                attributes: [NSKernAttributeName: spacing,
                             NSForegroundColorAttributeName: color])
            super.setAttributedTitle(attributedTitle, for: state)
        }
        else
        {
            super.setTitle(title, for: state)
        }
    }

    fileprivate func updateTitleLabel_()
    {
        let states:[UIControlState] = [.normal, .highlighted, .selected, .disabled]
        for state in states
        {
            let currentText = super.title(for: state)
            self.setTitle(currentText, for: state)
        }
    }

    @IBInspectable var spacing:CGFloat = 0 {
        didSet {
            updateTitleLabel_()
        }
    }
}
person hhamm    schedule 03.11.2016

Обновление для Swift 4 на основе ответа jaya raj.

extension UIButton{
    func addTextSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: (self.titleLabel?.text!)!)
        attributedString.addAttribute(NSAttributedStringKey.kern, value: spacing, range: NSRange(location: 0, length: (self.titleLabel?.text!.characters.count)!))
        self.setAttributedTitle(attributedString, for: .normal)
    }
}

extension UILabel{
    func addTextSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.text!)
        attributedString.addAttribute(NSAttributedStringKey.kern, value: spacing, range: NSRange(location: 0, length: self.text!.characters.count))
        self.attributedText = attributedString
    }
}

extension UITextField{
    func addPlaceholderSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.placeholder!)
        attributedString.addAttribute(NSAttributedStringKey.kern, value: spacing, range: NSRange(location: 0, length: self.placeholder!.characters.count))
        self.attributedPlaceholder = attributedString
    }
}

extension UINavigationItem{
    func addSpacing(spacing: CGFloat){
        let attributedString = NSMutableAttributedString(string: self.title!)
        attributedString.addAttribute(NSAttributedStringKey.kern, value: spacing, range: NSRange(location: 0, length: self.title!.characters.count))
        let label = UILabel()
        label.textColor = UIColor.black
        label.font = UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.bold)
        label.attributedText = attributedString
        label.sizeToFit()
        self.titleView = label
    }
}
person Levi Joraanstad    schedule 13.08.2019

Обновление для Swift 5 без принудительной распаковки:

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

func addTextSpacing(_ letterSpacing: CGFloat) {
    let attributedString = attributedTitle(for: .normal)?.mutableCopy() as? NSMutableAttributedString ??
        NSMutableAttributedString(string: title(for: .normal) ?? "")
    attributedString.addAttribute(NSAttributedString.Key.kern, value: letterSpacing,
                                  range: NSRange(location: 0, length: attributedString.string.count))
    self.setAttributedTitle(attributedString, for: .normal)
}
person Zaheer Moola    schedule 27.07.2020

Свифт 5

guard let buttonTitle = button.title(for: .normal) else { return }
    
    let attributedTitle = NSAttributedString(string: buttonTitle, attributes: [NSAttributedString.Key.kern: kernValue])
    button.setAttributedTitle(attributedTitle, for: .normal)
person Mayur Rathod    schedule 17.05.2021