batman
batman

Reputation: 2476

How to display NSMutableAttributedString in Text view in SwiftUI?

Given a string, The * quick * brown * fox * jumps * over * the * lazy * dog, I'm applying font modifiers as follows in order to style all occurrences of asterisk differently than the rest of the text.

func customDesc(_ text: String) -> NSMutableAttributedString {
        let asteriskTextRange = (text as NSString).range(of: "*")
        let attributedString = NSMutableAttributedString(string: text, attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 15, weight: .semibold)])
        attributedString.setAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 20, weight: .heavy)], range: asteriskTextRange)
        return attributedString
    }

It seems range(of:) will only pick the first occurrence so how do update all occurrences and display the resultant text in a Text view? I could not find any initialisers that accept NSMutableAttributedString. Any help is appreciated.

Upvotes: 1

Views: 1391

Answers (1)

Sweeper
Sweeper

Reputation: 271105

Texts take the Swift AttributedStrings instead of the NSAttributedStrings from Objective-C. You can convert to AttributedString simply by using one of its initialisers.

Text(AttributedString(customDesc(...)))

However, I would suggest that customDesc return a AttributedString directly, as it is more Swifty. You can use ranges(of:) to find all the ranges of a particular substring.

func customDesc(_ text: String) -> AttributedString {
    var attributedString = AttributedString(text)
    attributedString.font = Font.system(size: 15, weight: .semibold)

    for range in text.ranges(of: "*") {
        // this converts Range<String.Index> to Range<AttributedString.Index>
        if let lowerBound = AttributedString.Index(range.lowerBound, within: attributedString),
           let upperBound = AttributedString.Index(range.upperBound, within: attributedString) {
            let attrRange = lowerBound..<upperBound
            attributedString[attrRange].font = Font.system(size: 20, weight: .heavy)
        }
    }
    return attributedString
}
Text(customDesc(...))

Upvotes: 0

Related Questions