Project code:
–
Level:
SwiftUI’s Text component allows us to render more complex strings using AttributedString, but it’s only available for iOS 15 or higher.
var attributedString = AttributedString("Hello world!")
attributedString.foregroundColor = .red
If we want to use it with lower versions we can create a Text extension to create an init with NSAttributedString. Inside the init we have to iterate through each attribute of the string and concatenate a new text with the applied attribute:
extension Text {
init(_ attributedString: NSAttributedString) {
self.init("") // initial, empty Text
// scan the attributed string for distinctly attributed regions
attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length),
options: []) { (attrs, range, _) in
let string = attributedString.attributedSubstring(from: range).string
var text = Text(string)
// then, read applicable attributes and apply them to the Text
if let font = attrs[.font] as? UIFont {
// this takes care of the majority of formatting - text size, font family,
// font weight, if it's italic, etc.
text = text.font(.init(font))
}
if let color = attrs[.foregroundColor] as? UIColor {
text = text.foregroundColor(Color(color))
}
if let kern = attrs[.kern] as? CGFloat {
text = text.kerning(kern)
}
if #available(iOS 14.0, *) {
if let tracking = attrs[.tracking] as? CGFloat {
text = text.tracking(tracking)
}
}
if let strikethroughStyle = attrs[.strikethroughStyle] as? NSNumber,
strikethroughStyle != 0 {
if let strikethroughColor = (attrs[.strikethroughColor] as? UIColor) {
text = text.strikethrough(true, color: Color(strikethroughColor))
} else {
text = text.strikethrough(true)
}
}
if let underlineStyle = attrs[.underlineStyle] as? NSNumber,
underlineStyle != 0 {
if let underlineColor = (attrs[.underlineColor] as? UIColor) {
text = text.underline(true, color: Color(underlineColor))
} else {
text = text.underline(true)
}
}
if let baselineOffset = attrs[.baselineOffset] as? NSNumber {
text = text.baselineOffset(CGFloat(baselineOffset.floatValue))
}
// append the newly styled subtext to the rest of the text
self = self + text
}
}
}
Let’s test it in SwiftUI view:
struct ContentView: View {
private var string = NSAttributedString(string: "Hello world!", attributes: [
.font: UIFont.systemFont(ofSize: 72),
.foregroundColor: UIColor.red,
])
var body: some View {
VStack {
Text(string)
}
.padding()
}
}

With this solution the modifiers applied to Text don’t work, I haven’t figured out why yet.
Text(string)
.foregroundColor(.blue)
.font(.system(size: 12))
On the other hand, if we comment the foreground color attribute in the init for example, the color change works.
If someone manages to solve the problem of the modifiers in the view, put it in the comments and I’ll update the post.
Thank you for reading this post!
Leave a Reply