RichString
The easiest way to work with attributed strings in Swift
Introduction
This Swift framework was built to simplify working with NSAttributedString
. It does
so without adding additional types; it just extends the existing types that you already have,
ensuring that it is fully interoperable with any other method of using NSAttributedString
.
The core assumption this framework makes, is that you set up your attributed strings by first configuring all components appropriately, and then concatenating them.
It allows you to do things like this:
let title = "This is a title".fontSize(17).color(.blue)
let text = "This is some text".paragraphStyle {
$0.firstLineHeadIndent = 20
}
let content = title + text
Overview
This framework provides the following primitives. There are unit tests; have a look at them for more examples.
+
For Concatenating Attributed Strings
Operator Given two strings, you can append one to the other
using the +
operator:
let s1 = NSAttributedString()
let s2 = NSAttributedString()
let concatenated = s1 + s2
RichString
protocol for String
, NSString
and NSAttributedString
font(_:)
Apply the given font. The type Font
is a type
alias of UIFont
on iOS, and of NSFont
on macOS.
let attributedString = "text".font(.systemFont(ofSize: 12))
fontSize(_:)
Applies the given font size. If no font was set on
the attributed string yet, Font.systemFont
will be
assumed.
Note: unlike on iOS, on macOS this returns an optional attributed string instead.
let attributedString = "text".fontSize(12)
paragraphStyle(configure:)
Applies a paragraph style, configuring it with the
given closure. If the attributed string already had
a paragraph style attribute, the configure
closure
is called on that paragraph style; otherwise a new
NSMutableParagraphStyle
is used.
let attributedString = "Hello World".paragraphStyle {
$0.firstLineHeadIndent = 10
}
paragraphStyle(_:)
Applies the given paragraph style.
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.firstLineHeadIndent = 10
let attributedString = "text".paragraphStyle(paragraphStyle)
color(_:)
Applies the given (foreground) color.
let attributedString = "text".color(.blue)
backgroundColor(_:)
Applies the given background color.
let attributedString = "text".backgroundColor(.yellow)
ligature(_:)
Configures whether or not to use ligatures. Default is that they are used.
let attributedString = "text".ligature(false)
kern(_:)
Configures the amount with which to modify the
default kerning. The default 0
means that no
kerning change is applied.
let attributedString = "text".kern(0.1)
strikeThrough(style:)
Configures the strike through style.
Please note that depending on OS and version not all styles may actually work.
let attributedString = "text".strikeThrough(style: .styleSingle)
strikeThrough(color:)
Configures the strike through color. Only setting the color has no effect, the style must be configured as well.
let attributedString = "text".strikeThrough(color: .red)
strikeThrough(color:, style:)
Configures both the strike through color and style. Please note that depending on OS and version not all styles may actually work.
let attributedString = "text".strikeThrough(color: .red, style: .styleDouble)
underline(style:)
Configures the underline style. Please note that depending on OS and version not all styles may actually work.
let attributedString = "text".underline(style: .styleSingle)
underline(color:)
Configures the underline color. Only setting the color has no effect, the style must be configured as well.
let attributedString = "text".underline(color: .blue)
underline(color:, style:)
Configures both the underline color and style. Please note that depending on OS and version not all styles may actually work.
let attributedString = "text".underline(color: .blue, style: .styleSingle)
stroke(width:, color:)
Configures the stroke.
let attributedString = "text".stroke(width: 2, color: .green)
shadow(configure:)
Configures the shadow using a closure that receives
an NSShadow
instance. Not available on watchOS.
let result = "Hello World".shadow {
$0.shadowOffset = CGSize(width: 3, height: 3)
$0.shadowBlurRadius = 2
$0.shadowColor = Color.gray
}
shadow(_:)
Configures the shadow by setting an NSShadow
instance. Not available on watchOS.
let shadow = NSShadow()
shadow.shadowColor = .green
shadow.shadowBlurRadius = 2
shadow.shadowOffset = 3
let attributedString = "text".shadow(shadow)
letterPressed()
Adds the "letter pressed" text effect.
let attributedString = "text".letterPressed()
link(url:)
Creates hyperlink to the given URL with the receiver as text.
let url = URL(string: "https://example.com")
let attributedString = "text".link(url: url)
link(string:)
Creates hyperlink to the given URL with the receiver as text.
let urlString = "https://example.com"
let attributedString = "text".link(string: urlString)
attachment(configure:)
Creates a new NSTextAttachment
and passes it to the
configure
closure. Not available on watchOS.
let attributedString = NSAttributedString().attachment {
$0.image = UIImage(...)
$0.bounds = CGRect(...)
}
baselineOffset(_:)
Configures the baseline offset.
let attributedString = "text".baselineOffset(-0.5)
obliqueness(_:)
Configures the skew to be applied to glyphs.
let attributedString = "text".obliqueness(1.5)
expansion(_:)
Configures the expansion to be applied to glyphs.
let attributedString = "text".expansion(2)
NSAttributedString
Extension for Getting Attribute Values
All of the above methods have corresponding getters
to retrieve the attribute values from the attributed
string. The all return an optional; if the attribute
is not configured on the attributed string, nil
will be returned.
The getters are:
attachment: NSTextAttachment?
(not available on watchOS)backgroundColor: Color?
baselineOffset: Float?
color: Color?
expansion: Float?
fontSize: CGFloat?
isLetterPressed: Bool?
kern: Float?
ligature: Bool?
link: NSURL?
obliqueness: Float?
paragraphStyle: NSParagraphStyle?
shadow: NSShadow?
(not available on watchOS)strikeThroughColor: Color?
strikeThroughStyle: NSUnderlineStyle?
strokeColor: Color?
strokeWidth: Float?
underlineColor: Color?
underlineStyle: NSUnderlineStyle?
Usage
You can use the library any way you like, but two
easy ways are Carthage and CocoaPods. For CocoaPods,
put pod RichString
in your Podfile
.
Alternative Frameworks
I found a couple other frameworks that have the same goal as this one: simplifying using
NSAttributedString
. I like mine better, mostly because it has a simpler API that doesn't
use any additional types. But I'll let you choose for yourself.
TextAttributes is similar to this framework, but it
introduces a new type that you have to set up the attributes, instead of working directly on
the strings themselves. It doesn't feature the cool closure-based way of setting up
shadow { ... }
and paragraphStyle { ... }
that this framework has. And it doesn't provide
the super-convenient +
operator that this framework does. Finally, I didn't test this framework
on tvOS and watchOS. I'm rather confident that those will work as well, but you'll have to try.
Pull requests are wellcome of course.
TextAttributesUtil also introduces a new type for setting up the attributes. Also, it's API forces you to have more levels of nesting in your source code. It only supports iOS, not macOS.