SwiftRichString
👩🎨 Elegant Attributed String composition in Swift sauce
Install / Use
/learn @malcommac/SwiftRichStringREADME
SwiftRichString is a lightweight library which allows to create and manipulate attributed strings easily both in iOS, macOS, tvOS and even watchOS. It provides convenient way to store styles you can reuse in your app's UI elements, allows complex tag-based strings rendering and also includes integration with Interface Builder.
Main Features
| | Features Highlights | |--- |--------------------------------------------------------------------------------- | | 🦄 | Easy styling and typography managment with coincise declarative syntax | | 🏞 | Attach local images (lazy/static) and remote images inside text | | 🧬 | Fast & high customizable XML/HTML tagged string rendering | | 🌟 | Apply text transforms within styles | | 📐 | Native support for iOS 11 Dynamic Type | | 🖇 | Support for Swift 5.1's function builder to compose strings | | ⏱ | Compact code base with no external dependencies. | | 🐦 | Fully made in Swift 5 from Swift ❥ lovers |
Easy Styling
let style = Style {
$0.font = SystemFonts.AmericanTypewriter.font(size: 25) // just pass a string, one of the SystemFonts or an UIFont
$0.color = "#0433FF" // you can use UIColor or HEX string!
$0.underline = (.patternDot, UIColor.red)
$0.alignment = .center
}
let attributedText = "Hello World!".set(style: style) // et voilà!
XML/HTML tag based rendering
SwiftRichString allows you to render complex strings by parsing text's tags: each style will be identified by an unique name (used inside the tag) and you can create a StyleXML (was StyleGroup) which allows you to encapsulate all of them and reuse as you need (clearly you can register it globally).
// Create your own styles
let normal = Style {
$0.font = SystemFonts.Helvetica_Light.font(size: 15)
}
let bold = Style {
$0.font = SystemFonts.Helvetica_Bold.font(size: 20)
$0.color = UIColor.red
$0.backColor = UIColor.yellow
}
let italic = normal.byAdding {
$0.traitVariants = .italic
}
let myGroup = StyleXML(base: normal, ["bold": bold, "italic": italic])
let str = "Hello <bold>Daniele!</bold>. You're ready to <italic>play with us!</italic>"
self.label?.attributedText = str.set(style: myGroup)
That's the result!
<img src="Documentation_Assests/image_2.png" alt="" width=400px/>Documentation
- Introduction to
Style,StyleXML&StyleRegEx - The
StyleManager - Assign style using Interface Builder
- All properties of
Style
Other info:
<a name="styleStyleXML"/>Introduction to Style, StyleXML, StyleRegEx
The main concept behind SwiftRichString is the use of StyleProtocol as generic container of the attributes you can apply to both String and NSMutableAttributedString.
Concrete classes derivated by StyleProtocol are: Style, StyleXML and StyleRegEx.
Each of these classes can be used as source for styles you can apply to a string, substring or attributed string.
Style: apply style to strings or attributed strings
A Style is a class which encapsulate all the attributes you can apply to a string. The vast majority of the attributes of both AppKit/UIKit are currently available via type-safe properties by this class.
Creating a Style instance is pretty simple; using a builder pattern approach the init class require a callback where the self instance is passed and allows you to configure your properties by keeping the code clean and readable:
let style = Style {
$0.font = SystemFonts.Helvetica_Bold.font(size: 20)
$0.color = UIColor.green
// ... set any other attribute
}
let attrString = "Some text".set(style: style) // attributed string
StyleXML: Apply styles for tag-based complex string
Style instances are anonymous; if you want to use a style instance to render a tag-based plain string you need to include it inside a StyleXML. You can consider a StyleXML as a container of Styles (but, in fact, thanks to the conformance to a common StyleProtocol's protocol your group may contains other sub-groups too).
let bodyStyle: Style = ...
let h1Style: Style = ...
let h2Style: Style = ...
let group = StyleXML(base: bodyStyle, ["h1": h1Style, "h2": h2Style])
let attrString = "Some <h1>text</h1>, <h2>welcome here</h2>".set(style: group)
The following code defines a group where:
- we have defined a base style. Base style is the style applied to the entire string and can be used to provide a base ground of styles you want to apply to the string.
- we have defined two other styles named
h1andh2; these styles are applied to the source string when parser encounter some text enclosed by these tags.
StyleRegEx: Apply styles via regular expressions
StyleRegEx allows you to define a style which is applied when certain regular expression is matched inside the target string/attributed string.
let emailPattern = "([A-Za-z0-9_\\-\\.\\+])+\\@([A-Za-z0-9_\\-\\.])+\\.([A-Za-z]+)"
let style = StyleRegEx(pattern: emailPattern) {
$0.color = UIColor.red
$0.backColor = UIColor.yellow
}
let attrString = "My email is hello@danielemargutti.com and my website is http://www.danielemargutti.com".(style: style!)
The result is this:
<img src="Documentation_Assests/image_4.png" alt="" width=500px/> <a name="concatenation"/>String & Attributed String concatenation
SwiftRichString allows you to simplify string concatenation by providing custom + operator between String,AttributedString (typealias of NSMutableAttributedString) and Style.
This a an example:
let body: Style = Style { ... }
let big: Style = Style { ... }
let attributed: AttributedString = "hello ".set(style: body)
// the following code produce an attributed string by
// concatenating an attributed string and two plain string
// (one styled and another plain).
let attStr = attributed + "\(username)!".set(style:big) + ". You are welcome!"
You can also use + operator to add a style to a plain or attributed string:
// This produce an attributed string concatenating a plain
// string with an attributed string created via + operator
// between a plain string and a style
let attStr = "Hello" + ("\(username)" + big)
Finally you can concatente strings using function builders:
let bold = Style { ... }
let italic = Style { ... }
let attributedString = AttributedString.composing {
"hello".set(style: bold)
"world".set(style: italic)
}
<a name="manualstyling"/>
Apply styles to String & Attributed String
Both String and Attributed String (aka NSMutableAttributedString) has a come convenience methods you can use to create an manipulate attributed text easily via code:
Strings Instance Methods
set(style: String, range: NSRange? = nil): apply a globally registered style to the string (or a substring) by producing an attributed string.set(styles: [String], range: NSRange? = nil): apply an ordered sequence of globally registered styles to the string (or a substring) by producing an attributed string.set(style: StyleProtocol, range: NSRange? = nil): apply an instance ofStyleorStyleXML(to render tag-based text) to the string (or a substring) by producting an attributed string.set(styles: [StyleProtocol], range: NSRange? = nil): apply a sequence ofStyle/StyleXMLinstance in order to produce a single attributes collection which will be applied to the string (or substring) to produce an attributed string.
Some examples:
// apply a globally registered style named MyStyle to the entire string
let a1: AttributedString = "Hello world".set(style: "MyStyle")
// apply a style group to the entire string
// commonStyle will be applied to the entire string as base style
// styleH1 and styleH2 will be applied only for text inside that tags.
let styleH1: Style = ...
let styleH2: Style = ...
let StyleXML = StyleXML(base: commonStyle, ["h1" : styleH1, "h2" : styleH2])
let a2: AttributedString = "Hello <h1>world</h1>, <h2>welcome here</h2>".set(style: StyleXML)
// Apply a style defined via closure to a portion of the string
let a3 = "Hello Guys!".set(Style({ $0.font = SystemFonts.Helvetica_Bold.font(size: 20) }), range: NSMakeRange(0,4))
AttributedString Instance Methods
Similar methods are also available to attributed strings.
There are three categories of methods:
setmethods replace any existing attributes already set on target.addadd attributes defined by style/styles list to the targetremoveremove attributes defined from the receiver string.
Each of this method alter the receiver instance of the attributed string and also return the same instance in output (so chaining is allowed).
Add
add(style: String, range: NSRange? = nil): add to existing style of string/substring a globally registered style with given name.add(styles: [String], range: NSRange? = nil): add to the existing style of string/substring a style which is the sum of ordered sequences of globally registered styles with given name
