# SwiftRichString **Repository Path**: chuansong16/SwiftRichString ## Basic Information - **Project Name**: SwiftRichString - **Description**: Elegant, easy and swift-like way to create Attributed Strings - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-11-07 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README
## Documentation
- [Introduction to `Style`, `StyleXML` & `StyleRegEx`](#styleStyleXML)
- [String & Attributed String concatenation](#concatenation)
- [Apply styles to `String` & `Attributed String`](#manualstyling)
- [Fonts & Colors in `Style`](#fontscolors)
- [Derivating a `Style`](#derivatingstyle)
- [Support Dynamic Type](#dynamictype)
- [Render XML tagged strings](#customizexmlstrings)
- [Customize XML rendering: react to tag's attributes and unknown tags](#xmlstrings)
- [Custom text transforms](#texttransforms)
- [Local & Remote Images inside text](#images)
- [The `StyleManager`](#stylemanager)
- [Register globally available styles](#globalregister)
- [Defer style creation on demand](#defer)
- [Assign style using Interface Builder](#ib)
- [All properties of `Style`](#props)
Other info:
- [Requirements](#requirements)
- [Installation](#installation)
- [Contributing](#contributing)
- [Copyright](#copyright)
## 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:
```swift
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).
```swift
let bodyStyle: Style = ...
let h1Style: Style = ...
let h2Style: Style = ...
let group = StyleXML(base: bodyStyle, ["h1": h1Style, "h2": h2Style])
let attrString = "Some
## 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:
```swift
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:
```swift
// 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:
```swift
let bold = Style { ... }
let italic = Style { ... }
let attributedString = AttributedString.composing {
"hello".set(style: bold)
"world".set(style: italic)
}
```
## 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 of `Style` or `StyleXML` (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 of `Style`/`StyleXML` instance in order to produce a single attributes collection which will be applied to the string (or substring) to produce an attributed string.
Some examples:
```swift
// 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
where the `b` tag's blue color was overriden by the color tag attributes and the link in 'here' is clickable.
## Custom Text Transforms
Sometimes you want to apply custom text transforms to your string; for example you may want to make some text with a given style uppercased with current locale.
In order to provide custom text transform in `Style` instances just set one or more `TextTransform` to your `Style`'s `.textTransforms` property:
```swift
let allRedAndUppercaseStyle = Style({
$0.font = UIFont.boldSystemFont(ofSize: 16.0)
$0.color = UIColor.red
$0.textTransforms = [
.uppercaseWithLocale(Locale.current)
]
})
let text = "test".set(style: allRedAndUppercaseStyle) // will become red and uppercased (TEST)
```
While `TextTransform` is an enum with a predefined set of transform you can also provide your own function which have a `String` as source and another `String` as destination:
```swift
let markdownBold = Style({
$0.font = UIFont.boldSystemFont(ofSize: 16.0)
$0.color = UIColor.red
$0.textTransforms = [
.custom({
return "**\($0)**"
})
]
})
```
All text transforms are applied in the same ordered you set in `textTransform` property.
## Local & Remote Images inside text
SwiftRichString supports local and remote attached images along with attributed text.
You can create an attributed string with an image with a single line:
```swift
// You can specify the bounds of the image, both for size and the location respecting the base line of the text.
let localTextAndImage = AttributedString(image: UIImage(named: "rocket")!, bounds: CGRect(x: 0, y: -20, width: 25, height: 25))
// You can also load a remote image. If you not specify bounds size is the original size of the image.
let remoteTextAndImage = AttributedString(imageURL: "http://...")
// You can now compose it with other attributed or simple string
let finalString = "...".set(style: myStyle) + remoteTextAndImage + " some other text"
```
Images can also be loaded by rending an XML string by using the `img` tag (with `named` tag for local resource and `url` for remote url).
`rect` parameter is optional and allows you to specify resize and relocation of the resource.
```swift
let taggedText = """
Some text and this image:
Sometimes you may want to provide these images lazily. In order to do it just provide a custom implementation of the `imageProvider` callback in `StyleXML` instance:
```swift
let xmlText = "-
## Assign style using Interface Builder
SwiftRichString can be used also via Interface Builder.
- `UILabel`
- `UITextView`
- `UITextField`
has three additional properties:
- `styleName: String` (available via IB): you can set it to render the text already set via Interface Builder with a style registered globally before the parent view of the UI control is loaded.
- `style: StyleProtocol`: you can set it to render the text of the control with an instance of style instance.
- `styledText: String`: use this property, instead of `attributedText` to set a new text for the control and render it with already set style. You can continue to use `attributedText` and set the value using `.set()` functions of `String`/`AttributedString`.
Assigned style can be a `Style`, `StyleXML` or `StyleRegEx`:
- if style is a `Style` the entire text of the control is set with the attributes defined by the style.
- if style is a `StyleXML` a base attribute is set (if `base` is valid) and other attributes are applied once each tag is found.
- if style is a `StyleRegEx` a base attribute is set (if `base` is valid) and the attribute is applied only for matches of the specified pattern.
Typically you will set the style of a label via `Style Name` (`styleName`) property in IB and update the content of the control by setting the `styledText`:
```swift
// use `styleName` set value to update a text with the style
self.label?.styledText = "Another text to render" // text is rendered using specified `styleName` value.
```
Otherwise you can set values manually:
```swift
// manually set the an attributed string
self.label?.attributedText = (self.label?.text ?? "").set(myStyle)
// manually set the style via instance
self.label?.style = myStyle
self.label?.styledText = "Updated text"
```
## Properties available via `Style` class
The following properties are available:
| PROPERTY | TYPE | DESCRIPTION |
|-------------------------------|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
| size | `CGFloat` | font size in points |
| font | `FontConvertible` | font used in text |
| color | `ColorConvertible` | foreground color of the text |
| backColor | `ColorConvertible` | background color of the text |
| shadow | `NSShadow` | shadow effect of the text |
| underline | `(NSUnderlineStyle?,ColorConvertible?)` | underline style and color (if color is nil foreground is used) |
| strikethrough | `(NSUnderlineStyle?,ColorConvertible?)` | strikethrough style and color (if color is nil foreground is used) |
| baselineOffset | `Float` | character’s offset from the baseline, in point |
| paragraph | `NSMutableParagraphStyle` | paragraph attributes |
| lineSpacing | `CGFloat` | distance in points between the bottom of one line fragment and the top of the next |
| paragraphSpacingBefore | `CGFloat` | distance between the paragraph’s top and the beginning of its text content |
| paragraphSpacingAfter | `CGFloat` | space (measured in points) added at the end of the paragraph |
| alignment | `NSTextAlignment` | text alignment of the receiver |
| firstLineHeadIndent | `CGFloat` | distance (in points) from the leading margin of a text container to the beginning of the paragraph’s first line. |
| headIndent | `CGFloat` | The distance (in points) from the leading margin of a text container to the beginning of lines other than the first. |
| tailIndent | `CGFloat` | this value is the distance from the leading margin, If 0 or negative, it’s the distance from the trailing margin. |
| lineBreakMode | `LineBreak` | mode that should be used to break lines |
| minimumLineHeight | `CGFloat` | minimum height in points that any line in the receiver will occupy regardless of the font size or size of any attached graphic |
| maximumLineHeight | `CGFloat` | maximum height in points that any line in the receiver will occupy regardless of the font size or size of any attached graphic |
| baseWritingDirection | `NSWritingDirection` | initial writing direction used to determine the actual writing direction for text |
| lineHeightMultiple | `CGFloat` | natural line height of the receiver is multiplied by this factor (if positive) before being constrained by minimum and maximum line height |
| hyphenationFactor | `Float` | threshold controlling when hyphenation is attempted |
| ligatures | `Ligatures` | Ligatures cause specific character combinations to be rendered using a single custom glyph that corresponds to those characters |
| speaksPunctuation | `Bool` | Enable spoken of all punctuation in the text |
| speakingLanguage | `String` | The language to use when speaking a string (value is a BCP 47 language code string). |
| speakingPitch | `Double` | Pitch to apply to spoken content |
| speakingPronunciation | `String` | |
| shouldQueueSpeechAnnouncement | `Bool` | Spoken text is queued behind, or interrupts, existing spoken content |
| headingLevel | `HeadingLevel` | Specify the heading level of the text |
| numberCase | `NumberCase` | "Configuration for the number case, also known as ""figure style""" |
| numberSpacing | `NumberSpacing` | "Configuration for number spacing, also known as ""figure spacing""" |
| fractions | `Fractions` | Configuration for displyaing a fraction |
| superscript | `Bool` | Superscript (superior) glpyh variants are used, as in footnotes_. |
| `subscript` | `Bool` | Subscript (inferior) glyph variants are used: v_. |
| ordinals | `Bool` | Ordinal glyph variants are used, as in the common typesetting of 4th. |
| scientificInferiors | `Bool` | Scientific inferior glyph variants are used: H_O |
| smallCaps | `Set