84
votes

I have UIButton. In interface builder I set its title to be 'Attributed'. How can I make its title to be underlined from code in Swift?

@IBOutlet weak var myBtn: UIButton!

I created a function called on the touchUpInside event of this button:

var attributedString = NSMutableAttributedString(string:"new text")
    var attrs = [
        NSFontAttributeName : UIFont.systemFontOfSize(19.0),
        NSForegroundColorAttributeName : UIColor.redColor()
    ]
    var gString = NSMutableAttributedString(string:"g", attributes:attrs)
    attributedString.appendAttributedString(gString)

    myBtn.titleLabel?.attributedText = attributedString;

But still no result. Also I need to know how to access the underline attribute. Text, size and color stay the same.

14
thank you but not working for some reason also i need to know about underline attribute.moonvader

14 Answers

128
votes

Swift 5 / Xcode 12

  @IBOutlet weak var myButton: UIButton!
   
  let yourAttributes: [NSAttributedString.Key: Any] = [
      .font: UIFont.systemFont(ofSize: 14),
      .foregroundColor: UIColor.blue,
      .underlineStyle: NSUnderlineStyle.single.rawValue
  ] // .double.rawValue, .thick.rawValue
         
  
  override func viewDidLoad() {
     super.viewDidLoad()
    
     let attributeString = NSMutableAttributedString(
        string: "Your button text",
        attributes: yourAttributes
     )
     myButton.setAttributedTitle(attributeString, for: .normal)
  }

Swift 4 / Xcode 9

  @IBOutlet weak var myButton: UIButton!
   
  let yourAttributes: [NSAttributedStringKey: Any] = [
      NSAttributedStringKey.font: UIFont.systemFont(ofSize: 14),
      NSAttributedStringKey.foregroundColor: UIColor.blue,
      NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue
  ] // .styleDouble.rawValue, .styleThick.rawValue, .styleNone.rawValue             
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    let attributeString = NSMutableAttributedString(
      string: "Your button text",
      attributes: yourAttributes
    )
    myButton.setAttributedTitle(attributeString, for: .normal)
  }

Swift 3 / Xcode 8

  @IBOutlet weak var myButton: UIButton!

  let yourAttributes: [String: Any] = [
      NSFontAttributeName: UIFont.systemFont(ofSize: 14),
      NSForegroundColorAttributeName: UIColor.white,
      NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue
  ] // .styleDouble.rawValue, .styleThick.rawValue, .styleNone.rawValue             

   override func viewDidLoad() {
      super.viewDidLoad()

      let attributeString = NSMutableAttributedString(
        string: "Your button text",
        attributes: yourAttributes
      )        
      myButton.setAttributedTitle(attributeString, for: .normal) 
    }

enter image description here

98
votes

Here you go, just tested it. (works in xCode 7 Beta at least)

@IBOutlet weak var yourButton: UIButton!

var attrs = [
NSFontAttributeName : UIFont.systemFontOfSize(19.0),
NSForegroundColorAttributeName : UIColor.redColor(),
NSUnderlineStyleAttributeName : 1]

var attributedString = NSMutableAttributedString(string:"")

override func viewDidLoad() {
  super.viewDidLoad()

  let buttonTitleStr = NSMutableAttributedString(string:"My Button", attributes:attrs)
  attributedString.appendAttributedString(buttonTitleStr)
  yourButton.setAttributedTitle(attributedString, forState: .Normal)
}
33
votes

if you are looking for a way to do this without inheritance -

swift 3/4/5

// in swift 4 - switch NSUnderlineStyleAttributeName with NSAttributedStringKey.underlineStyle

extension UIButton {
    func underline() {
        guard let text = self.titleLabel?.text else { return }
        let attributedString = NSMutableAttributedString(string: text)
        //NSAttributedStringKey.foregroundColor : UIColor.blue
        attributedString.addAttribute(NSAttributedString.Key.underlineColor, value: self.titleColor(for: .normal)!, range: NSRange(location: 0, length: text.count))
        attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: self.titleColor(for: .normal)!, range: NSRange(location: 0, length: text.count))
        attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: text.count))
        self.setAttributedTitle(attributedString, for: .normal)
    }
}



extension UILabel {
    func underline() {
        if let textString = self.text {
            let attributedString = NSMutableAttributedString(string: textString)
            attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: attributedString.length - 1))
            attributedText = attributedString
        }
    }
}
31
votes

StoryBoard: If you want to Underline text from storyBoard.

  • Select button or label title as Attributed.
  • Select range of text which you want to underline.
  • Right click and choose Font then select underline.

enter image description here

19
votes

Based on some of previous answers I decide to make a class that can be easy implemented into your apps

Swift 4

import UIKit

class UnderlineTextButton: UIButton {

override func setTitle(_ title: String?, for state: UIControlState) {
    super.setTitle(title, for: .normal)
    self.setAttributedTitle(self.attributedString(), for: .normal)
}

private func attributedString() -> NSAttributedString? {
    let attributes : [NSAttributedStringKey : Any] = [
        NSAttributedStringKey.font : UIFont.systemFont(ofSize: 19.0),
        NSAttributedStringKey.foregroundColor : UIColor.red,
        NSAttributedStringKey.underlineStyle : NSUnderlineStyle.styleSingle.rawValue
    ]
    let attributedString = NSAttributedString(string: self.currentTitle!, attributes: attributes)
    return attributedString
  }
}

From code I call it on such a way button.setTitle(author, for: .normal)

15
votes

Thanks for posting your code, it wasn't clear that you knew how to create an attributed string at all.

This should work:

var attrs = [
    NSFontAttributeName : UIFont.systemFontOfSize(19.0),
    NSForegroundColorAttributeName : UIColor.redColor(),
    NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleSingle.rawValue
]

Swift 4 version:

var attrs : [NSAttributedStringKey : Any] = [
    NSAttributedStringKey.font : UIFont.systemFont(ofSize: 19.0),
    NSAttributedStringKey.foregroundColor : UIColor.red,
    NSAttributedStringKey.underlineStyle : NSUnderlineStyle.styleSingle.rawValue
]
11
votes

@ShlomoKoppel answer in Swift 4.2

extension UIButton {
    func underline() {
        guard let text = self.titleLabel?.text else { return }
        let attributedString = NSMutableAttributedString(string: text)
        //NSAttributedStringKey.foregroundColor : UIColor.blue
        attributedString.addAttribute(NSAttributedString.Key.underlineColor, value: self.titleColor(for: .normal)!, range: NSRange(location: 0, length: text.count))
        attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: self.titleColor(for: .normal)!, range: NSRange(location: 0, length: text.count))
        attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: text.count))
        self.setAttributedTitle(attributedString, for: .normal)
    }
}



extension UILabel {
    func underlineMyText() {
        if let textString = self.text {
            let attributedString = NSMutableAttributedString(string: textString)
            attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: attributedString.length - 1))
            attributedText = attributedString
        }
    }
}
7
votes

Here is done on the storyboard. (Xcode 9.1)

  1. Select the Button object in your view.
  2. Open Fonts Settings

enter image description here

  1. Select Single Underline

enter image description here

  1. Type your text, press [Enter]
5
votes

This is my solution. And to be honest you probably need this more than one place, so let's create an extension. This is swift 5.0 Cheers :)

extension UIButton {
    func underline() {
        guard let title = self.titleLabel else { return }
        guard let tittleText = title.text else { return }
        let attributedString = NSMutableAttributedString(string: (tittleText))
        attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: (tittleText.count)))
        self.setAttributedTitle(attributedString, for: .normal)
    }
}

And you can use it like this.

    override func viewDidLoad() {
     super.viewDidLoad()
     button.underline()
}
5
votes
  • Swift 5.2.4
  • Xcode 11.5
let attributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.underlineStyle: 1,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13),
NSAttributedString.Key.foregroundColor: UIColor.systemGray3
]

let attributedString = NSMutableAttributedString(string: "Text here", attributes: attributes)
button.setAttributedTitle(NSAttributedString(attributedString: attributedString), for: .normal)
4
votes

A modified version of @shlomo-koppel answer for button title, It will work if you set/change button title programmatically (like in my case I used localization)

extension UIButton {
    func underline() {
        guard let text = self.currentTitle else { return }
        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(NSAttributedString.Key.underlineColor, value: self.titleColor(for: .normal)!, range: NSRange(location: 0, length: text.count))
        attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: self.titleColor(for: .normal)!, range: NSRange(location: 0, length: text.count))
        attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: text.count))
        self.setAttributedTitle(attributedString, for: .normal)
    }
}
2
votes

For swift 5

var attrs : [NSAttributedString.Key : Any] = [
    NSAttributedString.Key.font : UIFont.systemFont(ofSize: 19.0),
    NSAttributedString.Key.foregroundColor : UIColor.blue,
    NSAttributedString.Key.underlineStyle : NSUnderlineStyle.styleSingle.rawValue
]
1
votes

Here you can add an underline and bold face too. You can just add an extention in your swift class file

Here is the extention (Swift 4 updated)

extension NSMutableAttributedString {
 @discardableResult func bold(_ text:String) -> NSMutableAttributedString {

      let attrs : [NSAttributedStringKey : Any] = [
        NSAttributedStringKey.font : UIFont(name: "Montserrat-Bold", size: 12)!,
        NSAttributedStringKey.foregroundColor : UIColor.white,
        NSAttributedStringKey.underlineStyle : NSUnderlineStyle.styleSingle.rawValue]
    let boldString = NSMutableAttributedString(string: text, attributes: attrs)
    self.append(boldString)
    return self
 }

 @discardableResult func normal(_ text:String)->NSMutableAttributedString {
      let attrs : [NSAttributedStringKey : Any] = [
        NSAttributedStringKey.font : UIFont(name: "Montserrat-Regular", size: 12)!,
        NSAttributedStringKey.foregroundColor : UIColor.white
    ]
    let normal =  NSAttributedString(string: text,  attributes:attrs)
    self.append(normal)
    return self
 }

}

You can use it like this:

let FormattedText = NSMutableAttributedString()
      FormattedText
           .normal("By signing in, you agree with our ")
           .bold("Terms of Service")

yourLabel.attributedText = FormattedText

and the Result will be display like this enter image description here

0
votes

May not be the best approach but I made an example to use it with a separated class and make only a one line call to get the text.

Here is my class:

import Foundation
import UIKit

enum AttributedTextsType {
    case underlined
    case bold
    case boldUnderlined
}

class AttributedTexts {
    private static func underlinedText(color: UIColor, size: CGFloat) -> [NSAttributedString.Key : Any] {
    let attrs = [
        NSAttributedString.Key.font : UIFont.systemFont(ofSize: size),
        NSAttributedString.Key.foregroundColor : color,
        NSAttributedString.Key.underlineStyle : 1] as [NSAttributedString.Key : Any]
    return attrs
    }

    private static func getAttibute(type: AttributedTextsType, color: UIColor, size: CGFloat) -> [NSAttributedString.Key : Any] {
        var attributes: [NSAttributedString.Key : Any]!
        switch type {
        case .underlined:
            attributes = AttributedTexts.underlinedText(color: color, size: size)
            break
        case .bold:
            attributes = AttributedTexts.underlinedText(color: color, size: size)
            break
        case .boldUnderlined:
            attributes = AttributedTexts.underlinedText(color: color, size: size)
            break
        }
        return attributes
    }

    static func set(string: String, color: UIColor, type: AttributedTextsType, size: CGFloat = 19.0) -> NSMutableAttributedString {
        let attributes = getAttibute(type: type, color: color, size: size)
        let attributedString = NSMutableAttributedString(string:"")
        let buttonTitleStr = NSMutableAttributedString(string: string, attributes: attributes)
        attributedString.append(buttonTitleStr)
        return attributedString
    }
}

Usage let attributedString = AttributedTexts.set(string: "Skip", color: .white, type: .underlined, size: 19.0)

Best regards