SwiftRichString
is a lightweight library wich allows you to simplify your work with attributed strings in UIKit. It provides convenient way to create and manage string with complex attributes, render tag-based string and manipulate styles at specified indexes.
Currently it's compatible with iOS and tvOS.
And, best of all, it's fully compatible with unicode (who don't love emoji?).
★★ Star our github repository to help us! ★★
Do you like SwiftRichString
? I'm also working on several other opensource libraries.
Take a look here:
- Hydra - Promises & Await/Async in Swift - Write better async code in Swift
- SwiftDate - Full features Dates & TimeZone management for iOS,macOS,tvOS and watchOS
- Hydra - Promise, Async/Await on sterioids!
- SwiftLocation - CoreLocation and Beacon Monitoring on steroid!
- SwiftScanner - String scanner in pure Swift with full unicode support
- SwiftSimplify - Tiny high-performance Swift Polyline Simplification Library
- SwiftMsgPack - MsgPack Encoder/Decoder in Swit
I've just wrote an article which cover the basic concepts of SwiftRichString. You can found it on Medium at Attributed String in Swift: the right way.
- Introduction
- Playground
- Define your own
Style
- Apply style to a
String
- Apply style on substring with
Range
- Apply style/s on substring with
NSRegularExpression
- Combine
Strings
andAttributed Strings
- Create tagged strings
- Parse and render tag-based content
- Available text attributes in
Style
- API Documentation
SwiftRichString
integrate seamlessy into UIKit/AppKit by allowing you to manage, combine and apply styles directly on NSMutableAttributedString
instances.
This library define only two main entities:
-
Style
is the central point ofSwiftRichString
: this class allows you to create easily and safety a collection of styles (align, text color, ligature, font etc.). In fact the ideal use-case is to create your own set of styles for your app, then apply to your strings. -
MarkupString
allows you to load a string which is pretty like a web page where your content can contain styles enclosed between classic html-style tags (ie. "<bold>Hello</bold> <nameStyle>\(username)</nameStyle>
).MarkupString
will parse data for your by generating a validNSMutableAttributedString
along your choosedStyles
. -
Also there are several
NSMutableAttributedString
andString
extensions allows you to play and combine strings and styles easily without introducing extra structures to your code and by mantaing readability.
If you want to play with SwiftRichString we have also made a small Playground.
Take a look at Playground.playground
file inside the SwiftRichString.xcworkspace
.
Style
is a class which define attributes you can apply to strings in a type-safe swifty way.
Each style has a name and a set of attributes you can set.
Creating Style
is pretty easy.
In this example we create a style which set a particular font with given size and color.
let big = Style("italic", {
$0.font = FontAttribute(.CourierNewPS_ItalicMT, size: 25)
$0.color = UIColor.red
})
This is also a special style called .default
.
Default - if present - is applied automatically before any other style to the entire sender string.
Other styles are applied in order just after it.
let def = Style.default {
$0.font = FontAttribute(.GillSans_Italic, size: 20)
}
Styles can be applied directly to String
instances (by generating NSMutableAttributedString
automatically) or on existing NSMutableAttributedString
.
In this example we can combine simple String
instances and apply your own set of styles:
// Define your own used styles
let bold = Style("bold", {
$0.font = FontAttribute(.CourierNewPS_BoldItalicMT, size: 30) // font + size
$0.color = UIColor.red // text color
$0.align = .center // align on center
})
let italic = Style("italic", {
$0.font = FontAttribute(.CourierNewPS_ItalicMT, size: 25)
$0.color = UIColor.green
})
let attributedString = ("Hello " + userName).set(style: bold) + "\nwelcome here".set(style: italic)
Will produce:
You can also apply one or more styles to a substring by passing a valid range. In this example we want to apply bold style to the "Man!" substring.
let style_bold = Style("bold", {
$0.font = FontAttribute(.Futura_CondensedExtraBold, size: 20)
})
let renderText = "Hello Man! Welcome".set(style: style_bold, range: 6..<10)
Will produce:
Regular expressions are also supported; you can add your own style/s to matched strings.
SwiftRichString
has fully unicode support.
let sourceText = "👿🏅the winner"
let attributedString = sourceText.set(styles: myStyle, pattern: "the winner", options: .caseInsensitive)
// another example
let sourceText = "prefix12 aaa3 prefix45"
let attributedText = sourceText.set(styles: myStyle, pattern: "fix([0-9])([0-9])", options: .caseInsensitive)
Will produce:
You can combine String
and NSMutableAttributedString
easily with +
operator.
For example:
let part1 = "Hello"
let part2 = "Mario"
let part3 = "Welcome here!"
// You can combine simple String and `NSMutableAttributedString`
// Resulting is an `NSMutableAttributedString` instance.
let result = part1 + " " + part2.set(style: bold) + " " + part3
You can avoid creating new instances of NSMutableAttributedString
and change directly your instance:
let attributedText = "Welcome".set(style: bold)
// Render a simple string with given style and happend it to the previous instance
attributedText.append(string: " mario! ", style: bold)
Is possible to append a MarkupString
to an NSMutableAttributedString
instance:
let sourceURL = URL(fileURLWithPath: "...")
let markUpObj = RichString(sourceURL, encoding: .utf8, [bold,italic])!
let finalAttributed = "Welcome!".set(style: bold)
// Create an `NSMutableAttributedString` render from markUpObj and append it to the instance
finalAttributed.append(markup: markUpObj)
Sometimes you may have a text you want to render with your own favorite application's styles, like HTML/CSS does with web page.
With SwiftRichString
it's really easy; add your favourite tags to your source string, create associated Style
and apply them.
Let me show an example:
// First of all we want to define all `Style` you want to use in your
// source string.
// Each style has its own name (any letter-based identifier) you should use in your source string
let tStyle1 = Style("style1", {
$0.font = FontAttribute(.AvenirNextCondensed_Medium, size: 50)
$0.color = UIColor.red
})
let tStyle2 = Style("style2", {
$0.font = FontAttribute(.HelveticaNeue_LightItalic, size: 20)
$0.color = UIColor.green
$0.backColor = UIColor.yellow
})
// Create and render text
let text = "Hello <style1>\(userName)!</style1>, <style2>welcome here!</style2>"
let renderedText = text.parse(tStyle1,tStyle2).text
MarkupString
allows you to load an tags-based string (even from a file, a literals or content from url) and parse it by applying with your own styles.
Suppose you have this text:
<center>The quick brown fox</center>\njumps over the lazy dogis an <italic>English-language</italic> pangram—a phrase that contains <italic>all</italic> of the letters of the alphabet. It is <extreme><bold>commonly</bold></extreme> used for touch-typing practice.
This text defines following styles: "center", "bold", "italic" and "extreme"
.
So, in order to render your text you may want create Style
instances which represent these tags:
let style_bold = Style("bold", {
$0.font = FontAttribute(.Futura_CondensedExtraBold, size: 15)
})
let style_center = Style("center", {
$0.font = FontAttribute(.Menlo_Regular, size: 15)
$0.align = .center
})
let style_italic = Style("italic", {
$0.font = FontAttribute(.HelveticaNeue_LightItalic, size: 15)
$0.color = UIColor.red
})
let style_exteme = Style("extreme", {
$0.font = FontAttribute(.TimesNewRomanPS_BoldItalicMT, size: 40)
$0.underline = UnderlineAttribute(color: UIColor.blue, style: NSUnderlineStyle.styleSingle)
})
let sourceTaggedString = "<center>The quick brown fox ...
let parser = try! MarkupString(source: sourceTaggedString, [style_center,style_italic,style_exteme,style_bold])
// Render attributes string
// Result is parsed only upon requested, only first time (then it will be cached).
let test_7 = parser.render(withStyles: [style_bold,style_center,style_italic,style_exteme])
Will produce:
Clearly you can load string also from file at specified URL
:
let sourceURL = URL(fileURLWithPath: "...")
let renderedText = RichString(sourceURL, encoding: .utf8, [bold,italic])!.text
func set(style: Style, range: Range<Int>? = nil) -> NSMutableAttributedString
Create an NSMutableAttributedString
from a simple String
instance by applying given style
at specified range.
If range
is missing style will be applied to the entire string.
func set(styles: Style...) -> NSMutableAttributedString
Create an NSMutableAttributedString
from a simple String
instance by applying given styles
.
Styles are applied in sequence as passed; the only exception is the .default
Style
if present; in this case .default
style is applied in first place.
func set(styles: Style..., pattern: String, options: NSRegularExpression.Options = .caseInsensitive) -> NSAttributedString
Create an NSMutableAttributedString
from a simple String
instance by applying given styles
with specified regular expression pattern.
Styles are applied in sequence as passed; the only exception is the .default
Style
if present; in this case .default
style is applied in first place.
func append(string: String, style: Style)
Append a String
instance to an existing NSMutableAttributedString
by applying given style
.
func append(markup string: MarkupString, styles: Style...)
Append a MarkupString
instance to an existing NSMutableAttributedString
by applying given styles
.
func add(style: Style, range: Range<Int>? = nil) -> NSMutableAttributedString
Append attributes defined by style
at given range
of existing NSMutableAttributedString
Return self
for chain purpose.
func add(styles: Style...) -> NSMutableAttributedString
Append attributes defined by passed styles
into current NSMutableAttributedString
.
Return self
for chain purpose.
func set(style: Style, range: Range<Int>? = nil) -> NSMutableAttributedString
Replace any exiting attribute into given range
with the one passed in style
.
Return self
for chain purpose.
func set(styles: Style...) -> NSMutableAttributedString
Replace any existing attribute into current instance of the attributed string with styles passed.
Styles are applied in sequence as passed; the only exception is the .default
Style
if present; in this case .default
style is applied in first place.
Return self
for chain purpose.
func remove(style: Style, range: Range<Int>? = nil) -> NSMutableAttributedString
Remove attributes keys defined in passed style
from the instance.
Combine between simple String
and NSMutableAttributedString
is pretty straightforward using the Swift's standard +
operator.
Just an example:
var test_1 = "Hello".set(style: bold) + "\n" + "World!".set(style: highlighted)
test_1.append(string: "\nHow old are you?", style: monospaced)
You can define your text attributes in type-safe Swift way. This is the list of attributes you can customize:
PROPERTY | DESCRIPTION | ATTRIBUTES |
`.align` | Text alignment | Any value of
NSTextAlignment. Example = `$0.align = .center` |
`.lineBreak` | The mode that should be used to break lines | Any value of
NSLineBreakMode. Example = `$0.lineBreak = .byWordWrapping` |
`.paragraphSpacing` | The space after the end of the paragraph. | `Float` Example: * `$0.paragraphSpacing = 4` Space measured in pointsadded at the end of the paragraph to separate it from the following paragraph. Always nonnegative. The space between paragraphs is determined by adding the previous paragraph�s paragraphSpacing. |
`.font` | Font & Font size to apply | FontAttribute FontAttribute is an helper enum which allows you to define in type safe Swift way font attributes. All system fonts are listed; you can however load a custom font from a string (classic mode) or extended FontAttribute enum to add your own custom font. Example: * `$0.font = FontAttribute(.CourierNewPS_BoldItalicMT, size: 30)` (from enum) * `$0.font = FontAttribute("MyCustomFontFamilyName", size: 40` (from raw string) |
`.color` | Text color | Any valid UIColor instance.
`SwiftRichString` also accepts UIColor from HEX string (like
"#FF4555") Example: * `$0.color = UIColor.red` * `$0.color = UIColor(hex: "#FF4555") |
`.backColor` | Background text color | Same of `.color` |
`.stroke` | Stroke attributes of text | `StrokeAttribute` `StrokeAttribute` is an helper class which also allows you to define a stroke's `.color` and `.width`. * `.color` (`UIColor`) color of the stroke; if not defined it is assumed to be the same as the value of color; otherwise, it describes the outline color. * `.width` (`CGFloat`) Amount to change the stroke width and is specified as a percentage of the font point size. Specify 0 (the default) for no additional changes. |
`.underline` | Underline attributes of text | `UnderlineAttribute` `UnderlineAttribute` is an helper struct which allows you to define `.color` and `.style` of the underline attribute. * `.color` (`UIColor`) Underline color, if missing same as foreground color. * `.style` (`NSUnderlineStyle`) The style of the underline, by default is `.styleNone` |
`.strike` | Strike attributes of text | `StrikeAttribute` `StrikeAttribute` is an helper struct which allows you to define strike attributes: `.color` and `.style`. * `.color` (`UIColor`) Underline color, if missing same as foreground color. * `.style` (`NSUnderlineStyle`) This value indicates whether the text is underlined and corresponds to one of the constants described in NSUnderlineStyle. |
`.shadow` | Shadow attributes of text (only for macOS and iOS) | `ShadowAttribute` `ShadowAttribute` defines following properties: * `.offset` (`CGSize`) horizontal and vertical offset values, specified using the width and height fields of the CGSize data type. * `.blurRadius` (`CGFloat`) This property contains the blur radius, as measured in the default user coordinate space. A value of 0 indicates no blur, while larger values produce correspondingly larger blurring. This value must not be negative. The default value is 0. * `.color` (`UIColor`) The default shadow color is black with an alpha of 1/3. If you set this property to nil, the shadow is not drawn. |
`.firstLineheadIntent` | The indentation of the first line. | `Float` Example: * `$0.firstLineHeadIntent = 0.5` The distance (in points) from the leading margin of a text container to the beginning of the paragraph�s first line. |
`.headIndent` | The indentation of lines other than the first. | `Float` Example: * `$0.headIdent = 4` The distance (in points) from the leading margin of a text container to the beginning of lines other than the first. This value is always nonnegative. |
`.tailIndent` | The trailing indentation. | `Float` Example: * `$0.tailIndent = 2` If positive, this value is the distance from the leading margin (for example, the left margin in left-to-right text). If 0 or negative, it�s the distance from the trailing margin. |
`.maximumLineHeight` | Maximum line height. | `Float` Example: * `$0.maximumLineHeight = 2` This property contains the maximum height in points that any line in the receiver will occupy, regardless of the font size or size ofany attached graphic. This value is always nonnegative. The default value is 0. Glyphs and graphics exceeding this height will overlap neighboring lines; however, a maximum height of 0 implies no line height limit. Although this limit applies to the line itself, line spacing adds extra space between adjacent lines. |
`.minimumLineHeight` | Minimum line height. | `Float` Example: * `$0.minimumLineHeight = 2` This property contains the minimum height in points that any line in the receiver will occupy, regardless of the font size or size of any attached graphic. This value is always nonnegative |
`.lineSpacing` | Distance in points between the bottom of one line fragment and the top of the next. | `Float` Example: * `$0.lineSpacing = 1` The distance in points between the bottom of one line fragment and the top of the next. This value is always nonnegative. This value is included in the line fragment heights in the layout manager. |
`.paragraphSpacingBefore` | Distance between the paragraph�s top and the beginning of its text content. | `Float` Example: * `$0.paragraphSpacingBefore = 1` The space (measured in points) between the paragraph�s top and the beginning of its text content. The default value of this property is 0.0. |
`.lineHeightMultiple` | Line height multiple. | `Float` Example: * `$0.lineHeightMultiple = 1` The natural line height of the receiver is multiplied by this factor (if positive) before being constrained by minimum and maximum line height. The default value of this property is 0.0. |
`.hyphenationFactor` | Paragraph�s threshold for hyphenation. | `Float` Example: * `$0.hyphenationFactor = 1` Hyphenation is attempted when the ratio of the text width (as broken without hyphenation) to the width of the line fragment is less than the hyphenation factor. When the paragraph�s hyphenation factor is 0.0, the layout manager�s hyphenation factor is used instead. When both are 0.0, hyphenation is disabled. |
You can install Swiftline using CocoaPods, carthage and Swift package manager
use_frameworks!
pod 'SwiftRichString'
github 'malcommac/SwiftRichString'
Add swiftline as dependency in your Package.swift
import PackageDescription
let package = Package(name: "YourPackage",
dependencies: [
.Package(url: "https://github.com/malcommac/SwiftRichString.git", majorVersion: 0),
]
)
Current version is compatible with:
- Swift 3.0+
- iOS 8.0 or later
- tvOS 9.0 or later
SwiftRichString is owned and maintained by Daniele Margutti.
As open source creation any help is welcome!
The code of this library is licensed under MIT License; you can use it in commercial products without any limitation.
The only requirement is to add a line in your Credits/About section with the text below:
This software uses open source SwiftRichString's library to manage rich attributed strings.
Web: http://github.com/malcommac/SwiftRichString
Created by Daniele Margutti and licensed under MIT License.