👩‍🎨 Elegant Attributed String composition in Swift sauce

Overview

SwiftLocation

Elegant Attributed String composition in Swift sauce

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!

Documentation

Other info:

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 h1 and h2; 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 [email protected] and my website is http://www.danielemargutti.com".(style: style!)

The result is this:

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)
}

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:

// 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:

  • set methods replace any existing attributes already set on target.
  • add add attributes defined by style/styles list to the target
  • remove remove 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 names.
  • add(style: StyleProtocol, range: NSRange? = nil): append passed style instance to string/substring by altering the receiver attributed string.
  • add(styles: [StyleProtocol], range: NSRange? = nil): append passed styles ordered sequence to string/substring by altering the receiver attributed string.

Set

  • set(style: String, range: NSRange? = nil): replace any existing style inside string/substring with the attributes defined inside the globally registered style with given name.
  • set(styles: [String], range: NSRange? = nil): replace any existing style inside string/substring with the attributes merge of the ordered sequences of globally registered style with given names.
  • set(style: StyleProtocol, range: NSRange? = nil): replace any existing style inside string/substring with the attributes of the passed style instance.
  • set(styles: [StyleProtocol], range: NSRange? = nil): replace any existing style inside string/substring with the attributes of the passed ordered sequence of styles.

Remove

  • removeAttributes(_ keys: [NSAttributedStringKey], range: NSRange): remove attributes specified by passed keys from string/substring.
  • remove(_ style: StyleProtocol): remove attributes specified by the style from string/substring.

Example:

let a = "hello".set(style: styleA)
let b = "world!".set(style: styleB)
let ab = (a + b).add(styles: [coupondStyleA,coupondStyleB]).remove([.foregroundColor,.font])

Fonts & Colors in Style

All colors and fonts you can set for a Style are wrapped by FontConvertible and ColorConvertible protocols.

SwiftRichString obviously implements these protocols for UIColor/NSColor, UIFont/NSFont but also for String. For Fonts this mean you can assign a font by providing directly its PostScript name and it will be translated automatically to a valid instance:

let firaLight: UIFont = "FiraCode-Light".font(ofSize: 14)
...
...
let style = Style {
	$0.font = "Jura-Bold"
	$0.size = 24
	...
}

On UIKit you can also use the SystemFonts enum to pick from a type-safe auto-complete list of all available iOS fonts:

let font1 = SystemFonts.Helvetica_Light.font(size: 15)
let font2 = SystemFonts.Avenir_Black.font(size: 24)

For Color this mean you can create valid color instance from HEX strings:

let color: UIColor = "#0433FF".color
...
...
let style = Style {
	$0.color = "#0433FF"
	...
}

Clearly you can still pass instances of both colors/fonts.

Derivating a Style

Sometimes you may need to infer properties of a new style from an existing one. In this case you can use byAdding() function of Style to produce a new style with all the properties of the receiver and the chance to configure additional/replacing attributes.

let initialStyle = Style {
	$0.font = SystemFonts.Helvetica_Light.font(size: 15)
	$0.alignment = right
}

// The following style contains all the attributes of initialStyle
// but also override the alignment and add a different foreground color.
let subStyle = bold.byAdding {
	$0.alignment = center
	$0.color = UIColor.red
}

Conforming to Dynamic Type

To support your fonts/text to dynammically scale based on the users preffered content size, you can implement style's dynamicText property. UIFontMetrics properties are wrapped inside DynamicText class.

let style = Style {
	$0.font = UIFont.boldSystemFont(ofSize: 16.0)
	$0.dynamicText = DynamicText {
		$0.style = .body
		$0.maximumSize = 35.0
		$0.traitCollection = UITraitCollection(userInterfaceIdiom: .phone)
    }
}

Render XML/HTML tagged strings

SwiftRichString is also able to parse and render xml tagged strings to produce a valid NSAttributedString instance. This is particularly useful when you receive dynamic strings from remote services and you need to produce a rendered string easily.

In order to render an XML string you need to create a compisition of all styles you are planning to render in a single StyleXML instance and apply it to your source string as just you made for a single Style.

For example:

// The base style is applied to the entire string
let baseStyle = Style {
	$0.font = UIFont.boldSystemFont(ofSize: self.baseFontSize * 1.15)
	$0.lineSpacing = 1
	$0.kerning = Kerning.adobe(-20)
}

let boldStyle = Style {
	$0.font = UIFont.boldSystemFont(ofSize: self.baseFontSize)
    $0.dynamicText = DynamicText {
    $0.style = .body
    $0.maximumSize = 35.0
    $0.traitCollection = UITraitCollection(userInterfaceIdiom: .phone)
    }
}
		
let italicStyle = Style {
	$0.font = UIFont.italicSystemFont(ofSize: self.baseFontSize)
}

// A group container includes all the style defined.
let groupStyle = StyleXML.init(base: baseStyle, ["b" : boldStyle, "i": italicStyle])

// We can render our string
let bodyHTML = "Hello <b>world!</b>, my name is <i>Daniele</i>"
self.textView?.attributedText = bodyHTML.set(style: group)

Customize XML rendering: react to tag's attributes and unknown tags

You can also add custom attributes to your tags and render it as you prefer: you need to provide a croncrete implementation of XMLDynamicAttributesResolver protocol and assign it to the StyleXML's .xmlAttributesResolver property.

The protocol will receive two kind of events:

  • applyDynamicAttributes(to attributedString: inout AttributedString, xmlStyle: XMLDynamicStyle) is received when parser encounter an existing style with custom attributes. Style is applied and event is called so you can make further customizations.
  • func styleForUnknownXMLTag(_ tag: String, to attributedString: inout AttributedString, attributes: [String: String]?) is received when a unknown (not defined in StyleXML's styles) tag is received. You can decide to ignore or perform customizations.

The following example is used to override text color for when used for any known tag:

// First define our own resolver for attributes
open class MyXMLDynamicAttributesResolver: XMLDynamicAttributesResolver {
    
    public func applyDynamicAttributes(to attributedString: inout AttributedString, xmlStyle: XMLDynamicStyle) {
        let finalStyleToApply = Style()
        xmlStyle.enumerateAttributes { key, value  in
            switch key {
                case "color": // color support
                    finalStyleToApply.color = Color(hexString: value)
                
                default:
                    break
            }
        }
        
        attributedString.add(style: finalStyleToApply)
    }
}

// Then set it to our's StyleXML instance before rendering text.
let groupStyle = StyleXML.init(base: baseStyle, ["b" : boldStyle, "i": italicStyle])
groupStyle.xmlAttributesResolver = MyXMLDynamicAttributesResolver()

The following example define the behaviour for a non known tag called rainbow.
Specifically it alter the string by setting a custom color for each letter of the source string.

open class MyXMLDynamicAttributesResolver: XMLDynamicAttributesResolver {

  public override func styleForUnknownXMLTag(_ tag: String, to attributedString: inout AttributedString, attributes: [String : String]?) {
        super.styleForUnknownXMLTag(tag, to: &attributedString, attributes: attributes)
        
        if tag == "rainbow" {
            let colors = UIColor.randomColors(attributedString.length)
            for i in 0..<attributedString.length {
                attributedString.add(style: Style({
                    $0.color = colors[i]
                }), range: NSMakeRange(i, 1))
            }
        }
        
    }
  }
}

You will receive all read tag attributes inside the attributes parameter.
You can alter attributes or the entire string received as inout parameter in attributedString property.

A default resolver is also provided by the library and used by default: StandardXMLAttributesResolver. It will support both color attribute in tags and <a href> tag with url linking.

let sourceHTML = "My <b color=\"#db13f2\">webpage</b> is really <b>cool</b>. Take a look <a href=\"http://danielemargutti.com\">here</a>"
        
let styleBase = Style({
    $0.font = UIFont.boldSystemFont(ofSize: 15)
})
        
let styleBold = Style({
    $0.font = UIFont.boldSystemFont(ofSize: 20)
    $0.color = UIColor.blue
})
        
let groupStyle = StyleXML.init(base: styleBase, ["b" : styleBold])
self.textView?.attributedText = sourceHTML.set(style: groupStyle)

The result is this:

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:

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:

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:

// 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.

let taggedText = """
  Some text and this image:
  <img named="rocket" rect="0,-50,30,30"/>
  
  This other is loaded from remote URL:
  <img url="https://www.macitynet.it/wp-content/uploads/2018/05/video_ApplePark_magg18.jpg"/>
"""

self.textView?.attributedText = taggedText.set(style: ...)

This is the result:

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:

let xmlText = "- <img named=\"check\" background=\"#0000\"/> has done!"
        
let xmlStyle = StyleXML(base: {
  /// some attributes for base style
})

// This method is called when a new `img` tag is found. It's your chance to
// return a custom image. If you return `nil` (or you don't implement this method)
// image is searched inside any bundled `xcasset` file.
xmlStyle.imageProvider = { (imageName, attributes) in
	switch imageName {
		case "check":
		   // create & return your own image
		default:
		   // ...
	}
}
        
self.textView?.attributedText = xmlText.set(style: x)

The StyleManager

Register globally available styles

Styles can be created as you need or registered globally to be used once you need. This second approach is strongly suggested because allows you to theme your app as you need and also avoid duplication of the code.

To register a Style or a StyleXML globally you need to assign an unique identifier to it and call register() function via Styles shortcut (which is equal to call StylesManager.shared).

In order to keep your code type-safer you can use a non-instantiable struct to keep the name of your styles, then use it to register style:

// Define a struct with your styles names
public struct StyleNames {
	public static let body: String = "body"
	public static let h1: String = "h1"
	public static let h2: String = "h2"
	
	private init { }
}

Then you can:

let bodyStyle: Style = ...
Styles.register(StyleNames.body, bodyStyle)

Now you can use it everywhere inside the app; you can apply it to a text just using its name:

let text = "hello world".set(StyleNames.body)

or you can assign body string to the styledText via Interface Builder designable property.

Defer style creation on demand

Sometimes you may need to return a particular style used only in small portion of your app; while you can still set it directly you can also defer its creation in StylesManager.

By implementing onDeferStyle() callback you have an option to create a new style once required: you will receive the identifier of the style.

Styles.onDeferStyle = { name in
			
	if name == "MyStyle" {
		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
		}
				
		return (StyleXML(base: normal, ["bold": bold, "italic": italic]), true)
	}
			
	return (nil,false)
}

The following code return a valid style for myStyle identifier and cache it; if you don't want to cache it just return false along with style instance.

Now you can use your style to render, for example, a tag based text into an UILabel: just set the name of the style to use.

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:

// 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:

// 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<SmallCaps> Configure small caps behavior.
stylisticAlternates StylisticAlternates Different stylistic alternates available for customizing a font.
contextualAlternates ContextualAlternates Different contextual alternates available for customizing a font.
kerning Kerning Tracking to apply.
traitVariants TraitVariant Describe trait variants to apply to the font

Requirements

  • Swift 5.1+
  • iOS 8.0+
  • macOS 11.0+
  • watchOS 2.0+
  • tvOS 11.0+

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate Alamofire into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'SwiftRichString'

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler. It is in early development, but Alamofire does support its use on supported platforms.

Once you have your Swift package set up, adding Alamofire as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "https://github.com/malcommac/SwiftRichString.git", from: "3.5.0")
]

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
To integrate SwiftRichString into your Xcode project using Carthage, specify it in your Cartfile:

github "malcommac/SwiftRichString"

Run carthage to build the framework and drag the built SwiftRichString.framework into your Xcode project.

Contributing

Issues and pull requests are welcome! Contributors are expected to abide by the Contributor Covenant Code of Conduct.

Copyright

SwiftRichString is available under the MIT license. See the LICENSE file for more info.

Daniele Margutti: [email protected], @danielemargutti

Comments
  • Xcode 9 (beta) compile error: Cannot express tuple conversion '(Int?, Element?)' to '(index: Int?, item: Style?)'

    Xcode 9 (beta) compile error: Cannot express tuple conversion '(Int?, Element?)' to '(index: Int?, item: Style?)'

    A compile error occurs when compiling with Xcode 9 (beta) using SwiftRichString (0.9.8). When having swift compiler version set to "Swift 3.2" I get the following error in file Extention.swift line 78:

    Cannot express tuple conversion '(Int?, Element?)' to '(index: Int?, item: Style?)'

    opened by MartijnvdV 14
  • iOS 13 - Setting the font property of a style always results in Times New Roman being used

    iOS 13 - Setting the font property of a style always results in Times New Roman being used

    Environment

    • Xcode 11 Beta 5
    • iPhone XS (iOS 13 Beta)

    Example

    When the following code is compiled with Xcode 11 and run on iOS 13 any styles that contain fonts stop working correctly.

    let text = "No issues here, <b>but this text is Times New Roman instead of the heavy system font</b>"
    
                
    let baseStyle = Style { $0.color = UIColor.green }
    let heavyFontStyle = Style { $0.font = UIFont.systemFont(ofSize: 14, weight: .heavy) }
                
    let styleGroup = StyleGroup(base: baseStyle, [ "b": heavyFontStyle ])
                
    let attributedText = text.set(style: styleGroup)
    
    

    Screenshot 2019-08-08 at 13 33 09

    bug 
    opened by LisaGonaus 13
  • linkURL issue with UITextView

    linkURL issue with UITextView

    I'm responding to a user tapping a link in a UITextView using UITextView.textView(_:, shouldInteractWith:, in:, interaction:). Unfortunately, when using style.linkURL = .string("someText://") to set up the attributed text for that text view, shouldInteractWith does not fire when the user taps the attributed link. However when I set the style attributes using NSAttributedString keys (like so style.set(attribute: "someText://", forKey: .link) the shouldInteractWith text view delegate fires correctly.

    I'd be interested in digging into a fix for this, however before I spent anytime on this, I'd like to check with those more knowledgable about the implementation to see if this is intended behavior.

    question 
    opened by jeremy6462 9
  • Fixed missing font attributes while rendering StyleGroup

    Fixed missing font attributes while rendering StyleGroup

    Hi, I've just updated from 2.0.1 to 2.0.2, and all my styles are gone…

    Before: img_0064 After: img_0065

                let baseFontSize: CGFloat = 16
                
                let headerStyle = Style {
                    $0.font = UIFont.boldSystemFont(ofSize: self.baseFontSize * 1.15)
                    $0.lineSpacing = 1
                    $0.kerning = Kerning.adobe(-20)
                }
                let boldStyle = Style {
                    $0.font = UIFont.boldSystemFont(ofSize: self.baseFontSize)
                }
                let italicStyle = Style {
                    $0.font = UIFont.italicSystemFont(ofSize: self.baseFontSize)
                }
    
                let style = StyleGroup(base: Style {
                    $0.font = UIFont.systemFont(ofSize: self.baseFontSize)
                    $0.lineSpacing = 2
                    $0.kerning = Kerning.adobe(-15)
                    }, [
                        "h3": headerStyle,
                        "h4": headerStyle,
                        "h5": headerStyle,
                        "strong": boldStyle,
                        "b": boldStyle,
                        "em": italicStyle,
                        "i": italicStyle,
                        "li": Style {
                            $0.paragraphSpacingBefore = self.baseFontSize / 2
                            $0.firstLineHeadIndent = self.baseFontSize
                            $0.headIndent = self.baseFontSize * 1.71
                        },
                        "sup": Style {
                            $0.font = UIFont.systemFont(ofSize: self.baseFontSize / 1.2)
                            $0.baselineOffset = Float(self.baseFontSize) / 3.5
                        }])
                
                attrString = bodyHTML.set(style: style)
    

    Original text is:

    <strong>Parler du don d'organe n'est plus tabou. Je me renseigne, j'en discute avec mes proches,... et je décide!</strong>  
    
    En Belgique, au début des années 2000, le nombre de donneurs d’organes avait tendance à diminuer et les listes d’attente à augmenter considérablement ayant comme corollaire une augmentation de la mortalité des patients inscrits sur les listes d’attente. 
    
    Soucieux de cette situation, en juin 2005, le Ministre en charge de la Santé publique a souhaité mettre sur pied une vaste campagne de sensibilisation entièrement dédiée au don d’organes. 
    
    Depuis, de nombreuses actions entreprises par le SPF Santé publique viennent renforcer toutes celles qui sont accomplies au quotidien par les coordinateurs de transplantation, les coordinateurs locaux de don, les associations de familles de donneurs, les associations de patients transplantés et ce, depuis de très nombreuses années. 
    
    <strong>Objectifs poursuivis</strong> 
    
    Les objectifs principaux de cette campagne sont: 
    <li style="text-align: justify;">• d’améliorer la sensibilisation au don auprès des différents groupes auxquels les messages s’adressent,</li>
    <li style="text-align: justify;">• d’inviter les citoyens à «oser» en parler en famille, entre amis, entre collègues. Aborder la mort – sa propre mort – reste relativement tabou pour beaucoup.</li> 
    
    <strong>Pour en savoir plus... <a href="http://www.health.belgium.be/fr/sante/prenez-soin-de-vous/debut-et-fin-de-vie/don-dorganes" target="_blank">www.health.belgium.be/fr/sante/prenez-soin-de-vous/debut-et-fin-de-vie/don-dorganes</a></strong>
    
    bug 
    opened by jdanthinne 6
  • SwiftRichString 2.x for Swift 3.x

    SwiftRichString 2.x for Swift 3.x

    After upgrading Xcode to version 9.3 I can't longer build the project.

    <unknown>:0: error: fatal error encountered while reading from module 'SwiftRichString'; please file a bug report with your project and the crash log
    <unknown>:0: note: compiling as Swift 3.3, with 'SwiftRichString' built as Swift 4.1 (this is supported but may expose additional compiler issues)
    
    Cross-reference to module 'Foundation'
    ... NSAttributedStringKey
    
    0  swift                    0x0000000107da8ffa PrintStackTraceSignalHandler(void*) + 42
    1  swift                    0x0000000107da83b6 SignalHandler(int) + 966
    2  libsystem_platform.dylib 0x00007fff5e65ff5a _sigtramp + 26
    3  libsystem_platform.dylib 000000000000000000 _sigtramp + 2711224512
    4  libsystem_c.dylib        0x00007fff5e48a312 abort + 127
    5  swift                    0x00000001054d6bae swift::ModuleFile::fatal(llvm::Error) + 2062
    6  swift                    0x00000001054e8f9a swift::ModuleFile::getTypeChecked(llvm::PointerEmbeddedInt<unsigned int, 31>) + 13418
    7  swift                    0x00000001054f7e17 swift::SILDeserializer::readSILFunction(llvm::PointerEmbeddedInt<unsigned int, 31>, swift::SILFunction*, llvm::StringRef, bool, bool) + 455
    8  swift                    0x000000010550b00c swift::SILDeserializer::getFuncForReference(llvm::StringRef) + 748
    9  swift                    0x000000010550c4cd swift::SILDeserializer::readVTable(llvm::PointerEmbeddedInt<unsigned int, 31>) + 605
    10 swift                    0x000000010520076b swift::SILLinkerVisitor::processClassDecl(swift::ClassDecl const*) + 91
    11 swift                    0x00000001052473c5 swift::SILModule::lookUpVTable(swift::ClassDecl const*) + 261
    12 swift                    0x000000010520038f swift::SILLinkerVisitor::linkInVTable(swift::ClassDecl*) + 31
    13 swift                    0x00000001051ffe45 swift::SILLinkerVisitor::process() + 517
    14 swift                    0x00000001051ffb6f swift::SILLinkerVisitor::processFunction(swift::SILFunction*) + 79
    15 swift                    0x0000000105246555 swift::SILModule::linkFunction(swift::SILFunction*, swift::SILOptions::LinkingMode) + 117
    16 swift                    0x0000000104f843c9 runOnFunctionRecursively(swift::SILFunction*, swift::FullApplySite, swift::SILOptions::LinkingMode, llvm::DenseSet<swift::SILFunction*, llvm::DenseMapInfo<swift::SILFunction*> >&, llvm::ImmutableSet<swift::SILFunction*, llvm::ImutContainerInfo<swift::SILFunction*> >::Factory&, llvm::ImmutableSet<swift::SILFunction*, llvm::ImutContainerInfo<swift::SILFunction*> >, swift::ClassHierarchyAnalysis*) + 4249
    17 swift                    0x0000000104f82e56 (anonymous namespace)::MandatoryInlining::run() + 342
    18 swift                    0x0000000104f04db9 swift::SILPassManager::runOneIteration() + 10217
    19 swift                    0x0000000104f081eb swift::runSILDiagnosticPasses(swift::SILModule&) + 2123
    20 swift                    0x0000000104407697 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 32167
    21 swift                    0x00000001043fde64 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 7908
    22 swift                    0x00000001043b28b5 main + 18917
    23 libdyld.dylib            0x00007fff5e3de115 start + 1
    24 libdyld.dylib            0x00000000000000a8 start + 2713853844
    
    question 
    opened by rafsouzap 4
  • Fixed internal parser

    Fixed internal parser

    When I apply tags to a very large text, the attributes start getting applied to strange locations in text. I tried playing with this but haven't yet detected a pattern.

    Question: Is there a size limit for the text being tagged?

    bug 
    opened by abumami 4
  • StyleXML issue with & character and other chars needs to be escaped

    StyleXML issue with & character and other chars needs to be escaped

    Hi there. Thanks for the amazing library. I have a problem with & character in my strings. Not sure if it was discussed already.

    When I use "Lorem ipsum".set(style: "name") - everything is good.

    But once I include & "Lorem & ipsum".set(style: "name") - the whole style (kerning, line spacing) is broken.

    Maybe I'm missing something? How to show the & character? Please advice. Thanks!

    UPD: I think this is the corresponding output:

    "Failed to generate attributed string from xml: XMLStringBuilderError(parserError: Error Domain=NSXMLParserErrorDomain Code=111 "(null)", line: 1, column: 8)"

    bug enhancement 
    opened by vvit 3
  • Using UILabel with a named image results in a color issue.

    Using UILabel with a named image results in a color issue.

    Expected Result

    When using <img named="SomeImage"> with a UILabel, I expect the image to render exactly as it would in a browser.

    Actual Result

    The image will render as a black&white image but tinted to the UILabel's color. In some cases it will just display the UIImage as solid white or solid black. There is some kind of interaction between the UILabel text color and the UIImage rendering.

    Steps to Reproduce

    • Download the Google Image https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png
    • Create a UILabel with a text color of black.
    • Use SwiftRichString to add a named image using the Google image.
    • Notice the Google letters will all render solid black.
    • Change the UILabel color to red and notice the image now renders solid red letters.
    bug 
    opened by nkavian 3
  • Added support for Dynamic Text

    Added support for Dynamic Text

    Why

    To support dynamic text size.

    Changes

    • Add DynamicText class to allow supporting Dynamic Type texts.
    • Add dynamicText property to style.
    • Update iOS Example with a style supporting dynamic type.
    • Update readme.

    I hope to be contributing 😄. It's related to #32

    enhancement 
    opened by marinofelipe 3
  • Fixed an issue with Style copying via `byAdding()` function

    Fixed an issue with Style copying via `byAdding()` function

    Hello.

    I would like to report/highlight the breaking changes of the latest versions.

    With this simple group declaration

    typealias MainFont = Font.HelveticaNeue
    
    enum Font {
        enum HelveticaNeue: String {
            case light = "Light"
            case bold = "Bold"
            case boldItalic = "BoldItalic"
            func with(size: CGFloat) -> UIFont {
                return UIFont(name: "HelveticaNeue-\(rawValue)", size: size)!
            }
        }
    }
    
    let normal = Style {
        $0.font = MainFont.light.with(size: 16)
    }
    
    let bold = normal.byAdding {
        $0.font = MainFont.bold.with(size: 16)
    }
    
    let bold_italic = normal.byAdding {
        $0.font = MainFont.boldItalic.with(size: 15)
    }
    
    let stylesDefs = [
        "bold": bold,
        "bold_italic": bold_italic,
    ]
    
    let defaultStyles = StyleGroup(base: normal, stylesDefs)
    

    And the following text:

    var text = "This search engine is specifically designed to solve <bold>crosswords</bold> or <bold>arrowords puzzles</bold>.\n\nIn order to solve a word, you can either enter its <bold>definition</bold> or its <bold>pattern</bold>.\n\n<bold_italic>For patterns, you can simply press the spacebar for each unknown letter.</bold_italic>"
    text.set(style: defaultStyles)
    

    The output with version 2.0.1 is as expected:

    swiftrichstring-2 0 1

    With version 2.0.2 I've this:

    swiftrichstring-2 0 2

    With version 2.0.3, this:

    swiftrichstring-2 0 3

    And the latest 2.0.4 is the worst:

    swiftrichstring-2 0 4

    I've tried to use your new declaration style

    let normal = Style {
        $0.font = SystemFonts.HelveticaNeue_Light.font(size: 16)
    }
    
    let bold = Style {
        $0.font = SystemFonts.HelveticaNeue_Bold.font(size: 16)
    }
    
    let bold_italic = Style {
        $0.font = SystemFonts.HelveticaNeue_BoldItalic.font(size: 15)
    }
    

    But it does not solve the issue, I keep getting the output of the last screenshot.

    So either it's a breaking change or it's a bug, but for now, I will force the use of version 2.0.1 as it is the only one who gives the expected output.

    bug 
    opened by tuxfamily 3
  • Dynamic value support for TagAttributes (ie. apply link value from an 'a'/'href' tag)

    Dynamic value support for TagAttributes (ie. apply link value from an 'a'/'href' tag)

    When trying to convert HTML to attributedText with this wonderful tool, the only thing I'm missing is a way to construct the linkURL with the content of a tag attribute.

    I've looked into your code and here's an idea: instead of taking an optional URL for the Style linkURL property, what about a "URLConvertible" type?

    Here's a draft of what it could look like, but I don't understand your parsing process (yet) to be able to fully implement it.

    //MARK: - URLConvertible
    
    /// An enumeration representing the source of the URL to be applied.
    ///
    /// - url: URL type.
    /// - string: String url.
    /// - tagAttribute: value of attribute from a parsed tag (ie: "href").
    /// - tagText: text content from a parsed tag.
    public enum URLConvertible {
        case url(URL)
        case string(String)
        case tagAttribute(String)
        case tagText
        
        func url(for tag: StyleGroup.TagAttribute?) -> URL? {
            switch self {
            case .url(let url):
                return url
            case .string(let string):
                return URL(string: string)
            case .tagAttribute(let attribute):
                return URL(string: tag.attributes[attribute])
            case .tagText:
                return URL(string: tag.content)
            }
        }
        
    }
    

    We could then just do the following:

    attrString.add(style: StyleGroup(["a" : Style {
        $0.linkURL = .tagAttribute("href")
    }]))
    
    enhancement 
    opened by jdanthinne 3
  • FEATURE REQUEST: A font

    FEATURE REQUEST: A font "size" attribute within StandardXMLAttributesResolver would be immensely useful.

    I've tried to implement this in my own subclass of StandardXMLAttributesResolver, however we don't seem to have enough access to the information required. Originally, I was going to implement it as a string point size (which would be normal), but given the font size of the active style, when the attribute is parsed may provide something specific to a device class, I thought it would be more useful to add an attribute called "fontScale" so that you could scale the font up or down.

    For this to work, I think we also need the ability to apply an attribute to whatever the "current" or "active" style is.

    e.g.

    "This is normal, <activeStyle fontScale="1.5">but this text is larger by half, and < activeStyle fontScale="0.5">this is smaller by half.; returning to normal size now".

    Would render something like:

    image

    opened by pkclsoft 0
  • How to not apply parent tag's style to child ones?

    How to not apply parent tag's style to child ones?

    I have following html:

      <li> Some item <strong>here</strong></li> 
      

    I add style to li tag to give them bullet points:

    let li = Style {
                $0.textTransforms = [
                    TextTransform.custom {
                        return "• " + $0
                    }
                ]
            }
    

    Because of li is the parent for tags inside of it, that text transformation is also applying to strong tag. So my strong tag having a bullet point. How to avoid it?

    opened by abayken 0
  • After updating Xcode to 13 beta 5, getting ambiguous error

    After updating Xcode to 13 beta 5, getting ambiguous error

    I have just updated xcode to 13 beta 5. After updating, I am getting the following error

    Screenshot 2021-08-29 at 11 38 45 PM

    I have tried clearing the cache and rebuilding the project after cleaning. Also I reinstalled using pod install.

    opened by ahsanaasim 3
  • Releases(3.7.2)
    • 3.7.2(Jul 7, 2020)

    • 3.7.1(Jan 27, 2020)

      Released on: 2020-01-27

      CHANGELOG:

      • #104 Fixed an issue with escaping strings. (original: StyleXML issue with & character and other chars needs to be escaped. Introduced a new XMLParsingOptions to StyleXML's xmlParsingOptions property called escapeString (active by default). This function replace all non-parsable characters (by the internal NSXMLParser to parsable string which does not break the internal styling.)
      Source code(tar.gz)
      Source code(zip)
    • 3.7.0(Jan 26, 2020)

      Released on: 2020-01-26

      IMPORTANT

      Use 3.7.1 release instead of this build.
      This build is affected by a bug in escaping string which prevents correct decoding of the XML string for StyleXML.

      CHANGELOG:

      • #104 StyleXML issue with & character and other chars needs to be escaped. Introduced a new XMLParsingOptions to StyleXML's xmlParsingOptions property called escapeString (active by default). This function replace all non-parsable characters (by the internal NSXMLParser to parsable string which does not break the internal styling.
      • #102 StandardXMLAttributesResolver not recognizing links if custom style is provided for "a" tag.
      Source code(tar.gz)
      Source code(zip)
    • 3.6.1(Jan 21, 2020)

    • 3.6.0(Jan 12, 2020)

      Released on: 2020-01-12

      CHANGELOG:

      • #101 Added support to provide custom UIImage instances in XML rendering via StyleXML's imageProvider.
      • #98 Fixed an bug with NSTextAttachment which alway tint any placed UIImage.
      Source code(tar.gz)
      Source code(zip)
    • 3.5.1(Dec 24, 2019)

      Released on: 2019-12-24

      CHANGELOG:

      • #97 Fixed iOS 8 package compatibility with localizedUppercased/lowercased/capitalized string (iOS 8.x is the minimum requirement)
      Source code(tar.gz)
      Source code(zip)
    • 3.5.0(Dec 21, 2019)

      Released on: 2019-12-22

      CHANGELOG:

      • #6 Added support to load local images inside attributed string
      • #95 Added support to load image from remote URL inside attributed string with optional resize and translation
      • #96 Added support for attributed string's composing via Swift 5.1 function builders
      • #93 Added •textTransforms to support live text content transform directly from style (uppercase, lowercase, capitalized and virtually any string transformation function)
      • #90 Fixed .numberSpacing paragraph attribute which is not correctly applied
      • #77 New rewritten XML/HTML tagged string parser with support for custom XML attributes (ie. you can pass <bold color="#d6d6d6"> and provide custom render actions or style overrides for color attribute)
      • #77 Support to handle unknown tag attributes inside the XML string and provide custom actions via XMLDynamicAttributesResolver
      • #94 Fixed error supporting Dynamic Type
      • #88 Setting nil styledText in UIKit control will reset the style as you expect
      Source code(tar.gz)
      Source code(zip)
    • 3.0.4(Dec 11, 2019)

    • 3.0.3(Sep 29, 2019)

    • 3.0.2(Sep 24, 2019)

      RELEASED ON: 2019-09-24

      CHANGELOG

      • #84 [FIX] iOS 13 - Setting the font property of a style always results in Times New Roman being used bug
      • #78 [CHG] Allow dashes in tag attribute names
      Source code(tar.gz)
      Source code(zip)
    • 3.0.1(Jul 20, 2019)

    • 3.0.0(Mar 28, 2019)

      Released on: 2019-03-28

      Changes:

      • #64 Fixed .styledTextdoesn't set a text on UILabel if no style is set (yet)
      • #71 Added Swift 5 compatibility
      • #70 Fixed regular expression to parse tag's attributes
      Source code(tar.gz)
      Source code(zip)
    • 2.1.0(Jan 19, 2019)

      Released on 2019-01-19

      Changelog

      • #60 Added support for iOS Dynamic Text
      • #45 Added dynamic value support for TagAttributes (ie. apply link value from an 'a'/'href' tag)
      • #47 Fixed an issue with Style copying via byAdding() function
      • #58 Fixed an issue with StyleRegEx which prevents application of font attributes
      Source code(tar.gz)
      Source code(zip)
    • 2.0.5(Sep 20, 2018)

      Released on: 2018-09-20

      CHANGES

      • #52 Added compatibility with Swift 4.2 / XCode 10
      • #48 Fixed an issue when rendering emojis and other unicode strings
      Source code(tar.gz)
      Source code(zip)
    • 2.0.4(Sep 4, 2018)

    • 2.0.3(Sep 4, 2018)

    • 2.0.2(Sep 3, 2018)

      Released on: 2018/09/03

      Changes

      • #35 Restore linkURL's attribute for StyleProtocol in 2.x branch
      • #37 Fixed font/size attributes which are not inherited correctly
      • #38 Added support for shadow as text attribute
      • #40 Fixed build failed with XCode 9.2/Swift 4 (compactMap implementation)
      • #41 Fixed ignored
        rendering
      • #42 Restored stroke attribute in Style
      • #43 Style's font/size is set to nil by default and not override previously set style; font owns attributes are applied only when font/size is explicitly set for Style
      Source code(tar.gz)
      Source code(zip)
    • 2.0.1(May 20, 2018)

    • 0.9.10(Sep 18, 2017)

    • 0.9.9(Jul 6, 2017)

      • #18 Added renderTags(withStyles:) func in String extension. It will a shortcut to parse an html-tagged string and return the NSMutableAttributedString instance.
      • #19 MarkupString classes does not throws anymore; when parsing fails to invalid strings it will return nil.
      • #5 A new function is added to parse multiple regular expressions and apply to each one one or more styles. It's called func set(regExpStyles: [RegExpPatternStyles], default dStyle: Style? = nil) -> NSMutableAttributedString and accepts an array of RegExpPatternStyles structs (which defines the regexp rule, options and and array of Style to apply on match). default parameter allows you to set a default style to apply before rules are evaluated.
      • #2 Resolved an issue with CocoaPods
      • #20 Added compatibility with watchOS, tvOS and macOS.
      Source code(tar.gz)
      Source code(zip)
    • 0.9.4(Dec 19, 2016)

    • 0.9.3(Dec 14, 2016)

    • 0.9.2(Dec 9, 2016)

    Owner
    Daniele Margutti
    iOS & macOS Engineer, UI/UX Lover. Continuous improvement is better than delayed perfection.
    Daniele Margutti
    More powerful label, attributed string builder and text parser.

    DDText More powerful label, attributed string builder and text parser. DDLabel More powerful label than UILabel, using TextKit. It supports features b

    Daniel 16 Nov 8, 2022
    Easy Attributed String Creator

    The main idea of this project is to have an online tool to be able to visually add formatting to a text and get back a swift and/or objective-c code t

    Andres Canal 283 Dec 27, 2022
    Swift String Validator. Simple lib for ios to validate string and UITextFields text for some criterias

    Swift String validator About Library for easy and fastest string validation based on сciterias. Instalation KKStringValidator is available through Coc

    Kostya 17 Dec 21, 2019
    µframework for Attributed strings.

    Attributed µframework for Attributed strings. What is Attributed? Attributed aims to be a drop in replacement to the current version of the NSAttribut

    Nicholas Maccharoli 754 Jan 9, 2023
    Easiest way to create an attributed UITextView (with support for multiple links and from html)

    AttributedTextView Easiest way to create an attributed UITextView (with support for multiple links and html). See the demo app and the playground for

    Edwin Vermeer 430 Nov 24, 2022
    A Swifty API for attributed strings

    SwiftyAttributes A Swifty API for attributed strings. With SwiftyAttributes, you can create attributed strings like so: let fancyString = "Hello World

    Eddie Kaiger 1.5k Jan 5, 2023
    Texstyle allows you to format iOS attributed strings easily.

    Texstyle allows you to format attributed strings easily. Features Applying attributes with strong typing and autocompletion Cache for attributes Subst

    Rosberry 79 Sep 9, 2022
    An easier way to compose attributed strings

    TextAttributes makes it easy to compose attributed strings. let attrs = TextAttributes() .font(name: "HelveticaNeue", size: 16) .foregroundCol

    Damien 2.2k Dec 31, 2022
    A simple library for building attributed strings, for a more civilized age.

    Veneer A simple library for building attributed strings, for a more civilized age. Veneer was created to make creating attributed strings easier to re

    Wess Cope 26 Dec 27, 2022
    A quick helper for setting attributed texts to UILabel.

    UILabelAttributedTextHelper A quick helper for setting attributed texts to UILabel. Sample usage: label.setAttributedText( leadingText: "H

    Glenn Posadas 5 Aug 24, 2022
    Croc is a swift emoji string parsing library

    Croc is a library for parsing emojis on iOS. It provides a simple and lightweight interface for detecting, generating, categorizing and managing emoji characters, making emoji-powered features an easy task for developers.

    Joe Kalash 127 Nov 20, 2022
    Great Swift String Pluralize Extension

    Pluralize.swift Great Swift String Pluralize Extension case-insensitive tons of rules for irregular nouns (plural form) supports uncountable nouns all

    Joshua Arvin Lat 193 Nov 8, 2022
    A comprehensive, lightweight string extension for Swift

    SwiftString SwiftString is a lightweight string extension for Swift. This library was motivated by having to search StackOverflow for common string op

    Andrew Mayne 1.6k Dec 30, 2022
    🌍⏩📄 Convert ISO8859 1-16 Encoded Text to String in Swift. Supports iOS, tvOS, watchOS and macOS.

    ISO8859 Convert ISO8859 1-16 Encoded Text to String in Swift. Usage let encoding = ISO8859.part1 let string = String([...], iso8859Encoding: encoding)

    Devran Cosmo Uenal 18 Jan 2, 2023
    A Cross-Platform String and Regular Expression Library written in Swift.

    Guitar ?? A Cross-Platform String and Regular Expression Library written in Swift. About This library seeks to add common string manipulation function

    Arthur Ariel Sabintsev 659 Dec 27, 2022
    Swift emoji string parsing library

    Croc is a library for parsing emojis on iOS. It provides a simple and lightweight interface for detecting, generating, categorizing and managing emoji

    Joe Kalash 125 Sep 27, 2021
    String (and more) validation for iOS

    Swift Validators ?? String validation for iOS. Contents Installation Walkthrough Usage Available validators License ReactiveSwift + SwiftValidators Wa

    George Kaimakas 241 Nov 13, 2022
    Easy string decoration with styles

    StyleDecorator Design string simply by linking attributes. Example Create Decorator with specific Style and link it at the end of needed string or wra

    Dmytro Pylypenko 15 Nov 4, 2021