dcbenji
dcbenji

Reputation: 4678

How do I make an attributed string using Swift?

I am trying to make a simple Coffee Calculator. I need to display the amount of coffee in grams. The "g" symbol for grams needs to be attached to my UILabel that I am using to display the amount. The numbers in the UILabel are changing dynamically with user input just fine, but I need to add a lower case "g" on the end of the string that is formatted differently from the updating numbers. The "g" needs to be attached to the numbers so that as the number size and position changes, the "g" "moves" with the numbers. I'm sure this problem has been solved before so a link in the right direction would be helpful as I've googled my little heart out.

I've searched through the documentation for an attributed string and I even downloded an "Attributed String Creator" from the app store, but the resulting code is in Objective-C and I am using Swift. What would be awesome, and probably helpful to other developers learning this language, is a clear example of creating a custom font with custom attributes using an attributed string in Swift. The documentation for this is very confusing as there is not a very clear path on how to do so. My plan is to create the attributed string and add it to the end of my coffeeAmount string.

var coffeeAmount: String = calculatedCoffee + attributedText

Where calculatedCoffee is an Int converted to a string and "attributedText" is the lowercase "g" with customized font that I am trying to create. Maybe I'm going about this the wrong way. Any help is appreciated!

Upvotes: 379

Views: 443960

Answers (30)

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119302

❌ Don't use the NSAttributedString which is an old Objective-C reference type API,

✅ Use the New AttributedString (without NS) which is a sendable struct instead!

Since 2021 and the release of iOS 15, macOS 12 and others, you can use the NEW AttributedString type which is an improved version of the the old NSAttributedString with value type semantics.

The API is very similar but more modern and with much less boiler plate. No more use of Dictionary and Any? types and safer to use!

For example after you define a simple AttributedString like this:

var myAttributedString = AttributedString("My Attributed String")

You can set attributes like:

Demo

myAttributedString.foregroundColor = .red

Demo

myAttributedString.backgroundColor = .yellow

Demo

myAttributedString.font = .largeTitle.bold()

Demo

myAttributedString.underlineStyle = .single
Combining attributes and attributed texts

You can also use a combination of style in a single text by simply appending them together:

Demo

var combinedString = myColoredText + myFontText + myUnderlinedText
// Add even more attributes on the combined text
combinedString = .yellow

More Attributes and advanced usage

There are a bunch of more attributes like the following but I highly recommend to see the full documentation here.

  • .strikethroughStyle
  • .kern
  • .tracking
  • .baselineOffset
  • .adaptiveImageGlyph (iOS 18.0 +)
  • .shadow
  • .accessibility

Upvotes: 0

Christopher
Christopher

Reputation: 193

SWIFT 6.0 - 2024

    func constructMessage() -> AttributedString {
        var mOne = AttributedString("Play on ")
        mOne.font = .body
        mOne.foregroundColor = .white
        
        var mTwo = AttributedString("Monday")
        mTwo.font = .body
        mTwo.foregroundColor = .yellow
        
        var mThree = AttributedString(" and ")
        mThree.font = .body
        mThree.foregroundColor = .white
        
        var mFour = AttributedString("Wednesday")
        mFour.font = .body
        mFour.foregroundColor = .yellow
        
        var mFive = AttributedString(" every week!")
        mFive.font = .body
        mFive.foregroundColor = .white
        
        return mOne + mTwo + mThree + mFour + mFive
    }
  

enter image description here

Upvotes: 0

Gurjinder Singh
Gurjinder Singh

Reputation: 10299

Swift 5

let attrStri = NSMutableAttributedString.init(string:"This is red")
let nsRange = NSString(string: "This is red")
        .range(of: "red", options: String.CompareOptions.caseInsensitive)
attrStri.addAttributes([
    NSAttributedString.Key.foregroundColor : UIColor.red,
    NSAttributedString.Key.font: UIFont.init(name: "PTSans-Regular", size: 15.0) as Any
], range: nsRange)
self.label.attributedText = attrStri

enter image description here

Upvotes: 22

Priyank Patel
Priyank Patel

Reputation: 870

Swift 3,4,5

Use below code for Text Color, Font, Background Color and Underline/Un derline Color

    let text = "swift is language"
    let attributes = [NSAttributedString.Key.foregroundColor: UIColor.red, NSAttributedString.Key.backgroundColor: UIColor.blue,NSAttributedString.Key.font: UIFont.systemFont(ofSize: 25.0),NSAttributedString.Key.underlineColor: UIColor.white,NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue] as [NSAttributedString.Key : Any]
        
    let textAttribute = NSAttributedString(string: text, attributes: attributes)
    swiftLabel1.attributedText = textAttribute

enter image description here

Upvotes: 6

H4B
H4B

Reputation: 59

Objective-C 2.0 example:

myUILabel.text = @"€ 60,00";
NSMutableAttributedString *amountText = [[NSMutableAttributedString alloc] initWithString:myUILabel.text];

//Add attributes you are looking for
NSDictionary *dictionaryOfAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                        [UIFont systemFontOfSize:12],NSFontAttributeName,
                                        [UIColor grayColor],NSForegroundColorAttributeName,
                                        nil];

//Will gray color and resize the € symbol
[amountText setAttributes:dictionaryOfAttributes range:NSMakeRange(0, 1)];
myUILabel.attributedText = amountText;

Upvotes: 0

Shalugin
Shalugin

Reputation: 1204

I did a function that takes array of strings and returns attributed string with the attributes you give.

func createAttributedString(stringArray: [String], attributedPart: Int, attributes: [NSAttributedString.Key: Any]) -> NSMutableAttributedString? {
    let finalString = NSMutableAttributedString()
    for i in 0 ..< stringArray.count {
        var attributedString = NSMutableAttributedString(string: stringArray[i], attributes: nil)
        if i == attributedPart {
            attributedString = NSMutableAttributedString(string: attributedString.string, attributes: attributes)
            finalString.append(attributedString)
        } else {
            finalString.append(attributedString)
        }
    }
    return finalString
}

In the example above you specify what part of string you want to get attributed with attributedPart: Int

And then you give the attributes for it with attributes: [NSAttributedString.Key: Any]

USE EXAMPLE

if let attributedString = createAttributedString(stringArray: ["Hello ", "how ", " are you?"], attributedPart: 2, attributes: [NSAttributedString.Key.foregroundColor: UIColor.systemYellow]) {
      myLabel.attributedText = attributedString
}

Will do:

Upvotes: 3

Vasily  Bodnarchuk
Vasily Bodnarchuk

Reputation: 25294

Details

  • Swift 5.2, Xcode 11.4 (11E146)

Solution

protocol AttributedStringComponent {
    var text: String { get }
    func getAttributes() -> [NSAttributedString.Key: Any]?
}

// MARK: String extensions

extension String: AttributedStringComponent {
    var text: String { self }
    func getAttributes() -> [NSAttributedString.Key: Any]? { return nil }
}

extension String {
    func toAttributed(with attributes: [NSAttributedString.Key: Any]?) -> NSAttributedString {
        .init(string: self, attributes: attributes)
    }
}

// MARK: NSAttributedString extensions

extension NSAttributedString: AttributedStringComponent {
    var text: String { string }

    func getAttributes() -> [Key: Any]? {
        if string.isEmpty { return nil }
        var range = NSRange(location: 0, length: string.count)
        return attributes(at: 0, effectiveRange: &range)
    }
}

extension NSAttributedString {

    convenience init?(from attributedStringComponents: [AttributedStringComponent],
                      defaultAttributes: [NSAttributedString.Key: Any],
                      joinedSeparator: String = " ") {
        switch attributedStringComponents.count {
        case 0: return nil
        default:
            var joinedString = ""
            typealias SttributedStringComponentDescriptor = ([NSAttributedString.Key: Any], NSRange)
            let sttributedStringComponents = attributedStringComponents.enumerated().flatMap { (index, component) -> [SttributedStringComponentDescriptor] in
                var components = [SttributedStringComponentDescriptor]()
                if index != 0 {
                    components.append((defaultAttributes,
                                       NSRange(location: joinedString.count, length: joinedSeparator.count)))
                    joinedString += joinedSeparator
                }
                components.append((component.getAttributes() ?? defaultAttributes,
                                   NSRange(location: joinedString.count, length: component.text.count)))
                joinedString += component.text
                return components
            }

            let attributedString = NSMutableAttributedString(string: joinedString)
            sttributedStringComponents.forEach { attributedString.addAttributes($0, range: $1) }
            self.init(attributedString: attributedString)
        }
    }
}

Usage

let defaultAttributes = [
    .font: UIFont.systemFont(ofSize: 16, weight: .regular),
    .foregroundColor: UIColor.blue
] as [NSAttributedString.Key : Any]

let marketingAttributes = [
    .font: UIFont.systemFont(ofSize: 20.0, weight: .bold),
    .foregroundColor: UIColor.black
] as [NSAttributedString.Key : Any]

let attributedStringComponents = [
    "pay for",
    NSAttributedString(string: "one",
                       attributes: marketingAttributes),
    "and get",
    "three!\n".toAttributed(with: marketingAttributes),
    "Only today!".toAttributed(with: [
        .font: UIFont.systemFont(ofSize: 16.0, weight: .bold),
        .foregroundColor: UIColor.red
    ])
] as [AttributedStringComponent]
let attributedText = NSAttributedString(from: attributedStringComponents, defaultAttributes: defaultAttributes)

Full Example

do not forget to paste the solution code here

import UIKit

class ViewController: UIViewController {

    private weak var label: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        let label = UILabel(frame: .init(x: 40, y: 40, width: 300, height: 80))
        label.numberOfLines = 2
        view.addSubview(label)
        self.label = label

        let defaultAttributes = [
            .font: UIFont.systemFont(ofSize: 16, weight: .regular),
            .foregroundColor: UIColor.blue
        ] as [NSAttributedString.Key : Any]

        let marketingAttributes = [
            .font: UIFont.systemFont(ofSize: 20.0, weight: .bold),
            .foregroundColor: UIColor.black
        ] as [NSAttributedString.Key : Any]

        let attributedStringComponents = [
            "pay for",
            NSAttributedString(string: "one",
                               attributes: marketingAttributes),
            "and get",
            "three!\n".toAttributed(with: marketingAttributes),
            "Only today!".toAttributed(with: [
                .font: UIFont.systemFont(ofSize: 16.0, weight: .bold),
                .foregroundColor: UIColor.red
            ])
        ] as [AttributedStringComponent]
        label.attributedText = NSAttributedString(from: attributedStringComponents, defaultAttributes: defaultAttributes)
        label.textAlignment = .center
    }
}

Result

enter image description here

Upvotes: 14

VipinYadav
VipinYadav

Reputation: 815

Use this sample code. This is very short code to achieve your requirement. This is working for me.

let attributes = [NSAttributedStringKey.font : UIFont(name: CustomFont.NAME_REGULAR.rawValue, size: CustomFontSize.SURVEY_FORM_LABEL_SIZE.rawValue)!]

let attributedString : NSAttributedString = NSAttributedString(string: messageString, attributes: attributes)

Upvotes: 4

Alvin George
Alvin George

Reputation: 14296

Swift 2.0

Here is a sample:

let newsString: NSMutableAttributedString = NSMutableAttributedString(string: "Tap here to read the latest Football News.")
newsString.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleDouble.rawValue], range: NSMakeRange(4, 4))
sampleLabel.attributedText = newsString.copy() as? NSAttributedString

Swift 5.x

let newsString: NSMutableAttributedString = NSMutableAttributedString(string: "Tap here to read the latest Football News.")
newsString.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue], range: NSMakeRange(4, 4))
sampleLabel.attributedText = newsString.copy() as? NSAttributedString

OR

let stringAttributes = [
    NSFontAttributeName : UIFont(name: "Helvetica Neue", size: 17.0)!,
    NSUnderlineStyleAttributeName : 1,
    NSForegroundColorAttributeName : UIColor.orangeColor(),
    NSTextEffectAttributeName : NSTextEffectLetterpressStyle,
    NSStrokeWidthAttributeName : 2.0]
let atrributedString = NSAttributedString(string: "Sample String: Attributed", attributes: stringAttributes)
sampleLabel.attributedText = atrributedString

Upvotes: 11

Vrezh Gulyan
Vrezh Gulyan

Reputation: 228

Swifter Swift has a pretty sweet way to do this without any work really. Just provide the pattern that should be matched and what attributes to apply to it. They're great for a lot of things check them out.

``` Swift
let defaultGenreText = NSAttributedString(string: "Select Genre - Required")
let redGenreText = defaultGenreText.applying(attributes: [NSAttributedString.Key.foregroundColor : UIColor.red], toRangesMatching: "Required")
``

If you have multiple places where this would be applied and you only want it to happen for specific instances then this method wouldn't work.

You can do this in one step, just easier to read when separated.

Upvotes: 1

Midhun
Midhun

Reputation: 2177

Swift 5 and above

   let attributedString = NSAttributedString(string:"targetString",
                                   attributes:[NSAttributedString.Key.foregroundColor: UIColor.lightGray,
                                               NSAttributedString.Key.font: UIFont(name: "Arial", size: 18.0) as Any])

Upvotes: 7

Kruiller
Kruiller

Reputation: 69

Please consider using Prestyler

import Prestyler
...
Prestyle.defineRule("$", UIColor.red)
label.attributedText = "\(calculatedCoffee) $g$".prestyled()

Upvotes: 0

Suragch
Suragch

Reputation: 511726

enter image description here

This answer has been updated for Swift 4.2.

Quick Reference

The general form for making and setting an attributed string is like this. You can find other common options below.

// create attributed string
let myString = "Swift Attributed String"
let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute) 

// set attributed text on a UILabel
myLabel.attributedText = myAttrString

Text Color

let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]

Background Color

let myAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]

Font

let myAttribute = [ NSAttributedString.Key.font: UIFont(name: "Chalkduster", size: 18.0)! ]

enter image description here

let myAttribute = [ NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue ]

enter image description here

let myShadow = NSShadow()
myShadow.shadowBlurRadius = 3
myShadow.shadowOffset = CGSize(width: 3, height: 3)
myShadow.shadowColor = UIColor.gray

let myAttribute = [ NSAttributedString.Key.shadow: myShadow ]

The rest of this post gives more detail for those who are interested.


Attributes

String attributes are just a dictionary in the form of [NSAttributedString.Key: Any], where NSAttributedString.Key is the key name of the attribute and Any is the value of some Type. The value could be a font, a color, an integer, or something else. There are many standard attributes in Swift that have already been predefined. For example:

  • key name: NSAttributedString.Key.font, value: a UIFont
  • key name: NSAttributedString.Key.foregroundColor, value: a UIColor
  • key name: NSAttributedString.Key.link, value: an NSURL or NSString

There are many others. See this link for more. You can even make your own custom attributes like:

  • key name: NSAttributedString.Key.myName, value: some Type.
    if you make an extension:

    extension NSAttributedString.Key {
        static let myName = NSAttributedString.Key(rawValue: "myCustomAttributeKey")
    }
    

Creating attributes in Swift

You can declare attributes just like declaring any other dictionary.

// single attributes declared one at a time
let singleAttribute1 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let singleAttribute2 = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
let singleAttribute3 = [ NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue ]

// multiple attributes declared at once
let multipleAttributes: [NSAttributedString.Key : Any] = [
    NSAttributedString.Key.foregroundColor: UIColor.green,
    NSAttributedString.Key.backgroundColor: UIColor.yellow,
    NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue ]

// custom attribute
let customAttribute = [ NSAttributedString.Key.myName: "Some value" ]

Note the rawValue that was needed for the underline style value.

Because attributes are just Dictionaries, you can also create them by making an empty Dictionary and then adding key-value pairs to it. If the value will contain multiple types, then you have to use Any as the type. Here is the multipleAttributes example from above, recreated in this fashion:

var multipleAttributes = [NSAttributedString.Key : Any]()
multipleAttributes[NSAttributedString.Key.foregroundColor] = UIColor.green
multipleAttributes[NSAttributedString.Key.backgroundColor] = UIColor.yellow
multipleAttributes[NSAttributedString.Key.underlineStyle] = NSUnderlineStyle.double.rawValue

Attributed Strings

Now that you understand attributes, you can make attributed strings.

Initialization

There are a few ways to create attributed strings. If you just need a read-only string you can use NSAttributedString. Here are some ways to initialize it:

// Initialize with a string only
let attrString1 = NSAttributedString(string: "Hello.")

// Initialize with a string and inline attribute(s)
let attrString2 = NSAttributedString(string: "Hello.", attributes: [NSAttributedString.Key.myName: "A value"])

// Initialize with a string and separately declared attribute(s)
let myAttributes1 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let attrString3 = NSAttributedString(string: "Hello.", attributes: myAttributes1)

If you will need to change the attributes or the string content later, you should use NSMutableAttributedString. The declarations are very similar:

// Create a blank attributed string
let mutableAttrString1 = NSMutableAttributedString()

// Initialize with a string only
let mutableAttrString2 = NSMutableAttributedString(string: "Hello.")

// Initialize with a string and inline attribute(s)
let mutableAttrString3 = NSMutableAttributedString(string: "Hello.", attributes: [NSAttributedString.Key.myName: "A value"])

// Initialize with a string and separately declared attribute(s)
let myAttributes2 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let mutableAttrString4 = NSMutableAttributedString(string: "Hello.", attributes: myAttributes2)

Changing an Attributed String

As an example, let's create the attributed string at the top of this post.

First create an NSMutableAttributedString with a new font attribute.

let myAttribute = [ NSAttributedString.Key.font: UIFont(name: "Chalkduster", size: 18.0)! ]
let myString = NSMutableAttributedString(string: "Swift", attributes: myAttribute )

If you are working along, set the attributed string to a UITextView (or UILabel) like this:

textView.attributedText = myString

You don't use textView.text.

Here is the result:

enter image description here

Then append another attributed string that doesn't have any attributes set. (Notice that even though I used let to declare myString above, I can still modify it because it is an NSMutableAttributedString. This seems rather unSwiftlike to me and I wouldn't be surprised if this changes in the future. Leave me a comment when that happens.)

let attrString = NSAttributedString(string: " Attributed Strings")
myString.append(attrString)

enter image description here

Next we'll just select the "Strings" word, which starts at index 17 and has a length of 7. Notice that this is an NSRange and not a Swift Range. (See this answer for more about Ranges.) The addAttribute method lets us put the attribute key name in the first spot, the attribute value in the second spot, and the range in the third spot.

var myRange = NSRange(location: 17, length: 7) // range starting at location 17 with a lenth of 7: "Strings"
myString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red, range: myRange)

enter image description here

Finally, let's add a background color. For variety, let's use the addAttributes method (note the s). I could add multiple attributes at once with this method, but I will just add one again.

myRange = NSRange(location: 3, length: 17)
let anotherAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
myString.addAttributes(anotherAttribute, range: myRange)

enter image description here

Notice that the attributes are overlapping in some places. Adding an attribute doesn't overwrite an attribute that is already there.

Related

Further Reading

Upvotes: 1094

iOS Developer
iOS Developer

Reputation: 472

Swift 3.0 // create attributed string

Define attributes like

let attributes = [NSAttributedStringKey.font : UIFont.init(name: "Avenir-Medium", size: 13.0)]

Upvotes: 0

Arunabh Das
Arunabh Das

Reputation: 14372

Swift 4.x

let attr = [NSForegroundColorAttributeName:self.configuration.settingsColor, NSFontAttributeName: self.configuration.settingsFont]

let title = NSAttributedString(string: self.configuration.settingsTitle,
                               attributes: attr)

Upvotes: 0

Debaprio B
Debaprio B

Reputation: 531

Swift 4.2

extension UILabel {

    func boldSubstring(_ substr: String) {
        guard substr.isEmpty == false,
            let text = attributedText,
            let range = text.string.range(of: substr, options: .caseInsensitive) else {
                return
        }
        let attr = NSMutableAttributedString(attributedString: text)
        let start = text.string.distance(from: text.string.startIndex, to: range.lowerBound)
        let length = text.string.distance(from: range.lowerBound, to: range.upperBound)
        attr.addAttributes([NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: self.font.pointSize)],
                           range: NSMakeRange(start, length))
        attributedText = attr
    }
}

Upvotes: 2

harthoo
harthoo

Reputation: 813

Xcode 6 version:

let attriString = NSAttributedString(string:"attriString", attributes:
[NSForegroundColorAttributeName: UIColor.lightGrayColor(), 
            NSFontAttributeName: AttriFont])

Xcode 9.3 version:

let attriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedStringKey.foregroundColor: UIColor.lightGray, 
            NSAttributedStringKey.font: AttriFont])

Xcode 10, iOS 12, Swift 4:

let attriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedString.Key.foregroundColor: UIColor.lightGray, 
            NSAttributedString.Key.font: AttriFont])

Upvotes: 21

Eugene Braginets
Eugene Braginets

Reputation: 856

 let attrString = NSAttributedString (
            string: "title-title-title",
            attributes: [NSAttributedStringKey.foregroundColor: UIColor.black])

Upvotes: 1

Neha
Neha

Reputation: 742

Swift 4

let attributes = [NSAttributedStringKey.font : UIFont(name: CustomFont.NAME_REGULAR.rawValue, size: CustomFontSize.SURVEY_FORM_LABEL_SIZE.rawValue)!]

let attributedString : NSAttributedString = NSAttributedString(string: messageString, attributes: attributes)

You need to remove the raw value in swift 4

Upvotes: 4

Yogesh Tandel
Yogesh Tandel

Reputation: 1754

func decorateText(sub:String, des:String)->NSAttributedString{
    let textAttributesOne = [NSAttributedStringKey.foregroundColor: UIColor.darkText, NSAttributedStringKey.font: UIFont(name: "PTSans-Bold", size: 17.0)!]
    let textAttributesTwo = [NSAttributedStringKey.foregroundColor: UIColor.black, NSAttributedStringKey.font: UIFont(name: "PTSans-Regular", size: 14.0)!]

    let textPartOne = NSMutableAttributedString(string: sub, attributes: textAttributesOne)
    let textPartTwo = NSMutableAttributedString(string: des, attributes: textAttributesTwo)

    let textCombination = NSMutableAttributedString()
    textCombination.append(textPartOne)
    textCombination.append(textPartTwo)
    return textCombination
}

//Implementation

cell.lblFrom.attributedText = decorateText(sub: sender!, des: " - \(convertDateFormatShort3(myDateString: datetime!))")

Upvotes: 5

Manas Mishra
Manas Mishra

Reputation: 57

extension String {
//MARK: Getting customized string
struct StringAttribute {
    var fontName = "HelveticaNeue-Bold"
    var fontSize: CGFloat?
    var initialIndexOftheText = 0
    var lastIndexOftheText: Int?
    var textColor: UIColor = .black
    var backGroundColor: UIColor = .clear
    var underLineStyle: NSUnderlineStyle = .styleNone
    var textShadow: TextShadow = TextShadow()

    var fontOfText: UIFont {
        if let font = UIFont(name: fontName, size: fontSize!) {
            return font
        } else {
            return UIFont(name: "HelveticaNeue-Bold", size: fontSize!)!
        }
    }

    struct TextShadow {
        var shadowBlurRadius = 0
        var shadowOffsetSize = CGSize(width: 0, height: 0)
        var shadowColor: UIColor = .clear
    }
}
func getFontifiedText(partOfTheStringNeedToConvert partTexts: [StringAttribute]) -> NSAttributedString {
    let fontChangedtext = NSMutableAttributedString(string: self, attributes: [NSFontAttributeName: UIFont(name: "HelveticaNeue-Bold", size: (partTexts.first?.fontSize)!)!])
    for eachPartText in partTexts {
        let lastIndex = eachPartText.lastIndexOftheText ?? self.count
        let attrs = [NSFontAttributeName : eachPartText.fontOfText, NSForegroundColorAttributeName: eachPartText.textColor, NSBackgroundColorAttributeName: eachPartText.backGroundColor, NSUnderlineStyleAttributeName: eachPartText.underLineStyle, NSShadowAttributeName: eachPartText.textShadow ] as [String : Any]
        let range = NSRange(location: eachPartText.initialIndexOftheText, length: lastIndex - eachPartText.initialIndexOftheText)
        fontChangedtext.addAttributes(attrs, range: range)
    }
    return fontChangedtext
}

}

//Use it like below

    let someAttributedText = "Some   Text".getFontifiedText(partOfTheStringNeedToConvert: <#T##[String.StringAttribute]#>)

Upvotes: -5

Efraim
Efraim

Reputation: 338

The best way to approach Attributed Strings on iOS is by using the built-in Attributed Text editor in the interface builder and avoid uneccessary hardcoding NSAtrributedStringKeys in your source files.

You can later dynamically replace placehoderls at runtime by using this extension:

extension NSAttributedString {
    func replacing(placeholder:String, with valueString:String) -> NSAttributedString {

        if let range = self.string.range(of:placeholder) {
            let nsRange = NSRange(range,in:valueString)
            let mutableText = NSMutableAttributedString(attributedString: self)
            mutableText.replaceCharacters(in: nsRange, with: valueString)
            return mutableText as NSAttributedString
        }
        return self
    }
}

Add a storyboard label with attributed text looking like this.

enter image description here

Then you simply update the value each time you need like this:

label.attributedText = initalAttributedString.replacing(placeholder: "<price>", with: newValue)

Make sure to save into initalAttributedString the original value.

You can better understand this approach by reading this article: https://medium.com/mobile-appetite/text-attributes-on-ios-the-effortless-approach-ff086588173e

Upvotes: 11

Andres
Andres

Reputation: 11747

I created an online tool that is going to solve your problem! You can write your string and apply styles graphically and the tool gives you objective-c and swift code to generate that string.

Also is open source so feel free to extend it and send PRs.

Transformer Tool

Github

enter image description here

Upvotes: 9

Adam Bardon
Adam Bardon

Reputation: 3899

Swift 4:

let attributes = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 17)!, 
                  NSAttributedStringKey.foregroundColor: UIColor.white]

Upvotes: 20

Sebastian
Sebastian

Reputation: 39

The attributes can be setting directly in swift 3...

    let attributes = NSAttributedString(string: "String", attributes: [NSFontAttributeName : UIFont(name: "AvenirNext-Medium", size: 30)!,
         NSForegroundColorAttributeName : UIColor .white,
         NSTextEffectAttributeName : NSTextEffectLetterpressStyle])

Then use the variable in any class with attributes

Upvotes: 2

Pavel Sharanda
Pavel Sharanda

Reputation: 944

It will be really easy to solve your problem with the library I created. It is called Atributika.

let calculatedCoffee: Int = 768
let g = Style("g").font(.boldSystemFont(ofSize: 12)).foregroundColor(.red)
let all = Style.font(.systemFont(ofSize: 12))

let str = "\(calculatedCoffee)<g>g</g>".style(tags: g)
    .styleAll(all)
    .attributedString

label.attributedText = str

768g

You can find it here https://github.com/psharanda/Atributika

Upvotes: 1

MendyK
MendyK

Reputation: 1488

I would highly recommend using a library for attributed strings. It makes it much easier when you want, for example, one string with four different colors and four different fonts. Here is my favorite. It is called SwiftyAttributes

If you wanted to make a string with four different colors and different fonts using SwiftyAttributes:

let magenta = "Hello ".withAttributes([
    .textColor(.magenta),
    .font(.systemFont(ofSize: 15.0))
    ])
let cyan = "Sir ".withAttributes([
    .textColor(.cyan),
    .font(.boldSystemFont(ofSize: 15.0))
    ])
let green = "Lancelot".withAttributes([
    .textColor(.green),
    .font(.italicSystemFont(ofSize: 15.0))

    ])
let blue = "!".withAttributes([
    .textColor(.blue),
    .font(.preferredFont(forTextStyle: UIFontTextStyle.headline))

    ])
let finalString = magenta + cyan + green + blue

finalString would show as

Shows as image

Upvotes: 23

Dipak Panchasara
Dipak Panchasara

Reputation: 39

extension UILabel{
    func setSubTextColor(pSubString : String, pColor : UIColor){    
        let attributedString: NSMutableAttributedString = self.attributedText != nil ? NSMutableAttributedString(attributedString: self.attributedText!) : NSMutableAttributedString(string: self.text!);

        let range = attributedString.mutableString.range(of: pSubString, options:NSString.CompareOptions.caseInsensitive)
        if range.location != NSNotFound {
            attributedString.addAttribute(NSForegroundColorAttributeName, value: pColor, range: range);
        }
        self.attributedText = attributedString
    }
}

Upvotes: 2

Alessandro Ornano
Alessandro Ornano

Reputation: 35392

Swift 2.1 - Xcode 7

let labelFont = UIFont(name: "HelveticaNeue-Bold", size: 18)
let attributes :[String:AnyObject] = [NSFontAttributeName : labelFont!]
let attrString = NSAttributedString(string:"foo", attributes: attributes)
myLabel.attributedText = attrString

Upvotes: 3

NRitH
NRitH

Reputation: 13893

Swift uses the same NSMutableAttributedString that Obj-C does. You instantiate it by passing in the calculated value as a string:

var attributedString = NSMutableAttributedString(string:"\(calculatedCoffee)")

Now create the attributed g string (heh). Note: UIFont.systemFontOfSize(_) is now a failable initializer, so it has to be unwrapped before you can use it:

var attrs = [NSFontAttributeName : UIFont.systemFontOfSize(19.0)!]
var gString = NSMutableAttributedString(string:"g", attributes:attrs)

And then append it:

attributedString.appendAttributedString(gString)

You can then set the UILabel to display the NSAttributedString like this:

myLabel.attributedText = attributedString

Upvotes: 118

Related Questions