Skip to content

Instantly share code, notes, and snippets.

@mmdock
Created May 13, 2021 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmdock/0167f09c2f8191e0b18ae7bb49991e12 to your computer and use it in GitHub Desktop.
Save mmdock/0167f09c2f8191e0b18ae7bb49991e12 to your computer and use it in GitHub Desktop.
import UIKit
public struct TextStyle: Equatable {
// MARK: - Instance Properties
public let font: UIFont?
public let color: UIColor?
public let backgroundColor: UIColor?
public let strikethrough: Bool
public let underline: Bool
public let paragraphSpacing: CGFloat?
public let paragraphIndent: CGFloat?
public let lineHeight: CGFloat?
public let letterSpacing: CGFloat?
public let lineBreakMode: NSLineBreakMode?
public let alignment: NSTextAlignment?
public let link: URL?
// MARK: - Initializers
public init(
font: UIFont? = nil,
color: UIColor? = nil,
backgroundColor: UIColor? = nil,
strikethrough: Bool = false,
underline: Bool = false,
paragraphSpacing: CGFloat? = nil,
paragraphIndent: CGFloat? = nil,
lineHeight: CGFloat? = nil,
letterSpacing: CGFloat? = nil,
lineBreakMode: NSLineBreakMode? = nil,
alignment: NSTextAlignment? = nil,
link: URL? = nil
) {
self.font = font
self.color = color
self.backgroundColor = backgroundColor
self.strikethrough = strikethrough
self.underline = underline
self.paragraphSpacing = paragraphSpacing
self.paragraphIndent = paragraphIndent
self.lineHeight = lineHeight
self.letterSpacing = letterSpacing
self.lineBreakMode = lineBreakMode
self.alignment = alignment
self.link = link
}
// MARK: - Instance Methods
private func attributes(paragraphStyle: NSParagraphStyle?) -> [NSAttributedString.Key: Any] {
var attributes: [NSAttributedString.Key: Any] = [:]
if let paragraphStyle = paragraphStyle {
attributes[.paragraphStyle] = paragraphStyle
}
if let font = font {
attributes[.font] = font
}
if let color = color {
attributes[.foregroundColor] = color
}
if let backgroundColor = backgroundColor {
attributes[.backgroundColor] = backgroundColor
}
if strikethrough {
attributes[.strikethroughStyle] = NSUnderlineStyle.single.rawValue
}
if underline {
attributes[.underlineStyle] = NSUnderlineStyle.single.rawValue
}
if let letterSpacing = letterSpacing {
attributes[.kern] = letterSpacing
}
if let link = link {
attributes[.link] = link
}
return attributes
}
// MARK: -
public func paragraphStyle() -> NSParagraphStyle {
let paragraphStyle = NSMutableParagraphStyle()
if let lineHeight = lineHeight {
paragraphStyle.minimumLineHeight = lineHeight
paragraphStyle.maximumLineHeight = lineHeight
}
if let paragraphSpacing = paragraphSpacing {
paragraphStyle.paragraphSpacing = paragraphSpacing
}
if let paragraphIndent = paragraphIndent {
paragraphStyle.firstLineHeadIndent = paragraphIndent
}
if let lineBreakMode = lineBreakMode {
paragraphStyle.lineBreakMode = lineBreakMode
}
if let alignment = alignment {
paragraphStyle.alignment = alignment
}
return paragraphStyle
}
public func attributes(includingParagraphStyle: Bool = true) -> [NSAttributedString.Key: Any] {
if includingParagraphStyle {
return attributes(paragraphStyle: paragraphStyle())
} else {
return attributes(paragraphStyle: nil)
}
}
public func attributedString(
_ string: String,
includingParagraphStyle: Bool = true
) -> NSAttributedString {
return NSAttributedString(string: string, style: self, includingParagraphStyle: includingParagraphStyle)
}
public func mutableString(
_ string: String,
includingParagraphStyle: Bool = true
) -> NSMutableAttributedString {
return NSMutableAttributedString(string: string, style: self, includingParagraphStyle: includingParagraphStyle)
}
// MARK: -
public func withFont(_ font: UIFont?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withColor(_ color: UIColor?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withBackgroundColor(_ backgroundColor: UIColor?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withStrikethrough(_ strikethrough: Bool) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withUnderline(_ underline: Bool) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withParagraphSpacing(_ paragraphSpacing: CGFloat?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withParagraphIndent(_ paragraphIndent: CGFloat?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withLineHeight(_ lineHeight: CGFloat?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withLetterSpacing(_ letterSpacing: CGFloat?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withLineBreakMode(_ lineBreakMode: NSLineBreakMode?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withAlignment(_ alignment: NSTextAlignment?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withLink(_ link: URL?) -> TextStyle {
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
public func withLink(_ stringLink: String) -> TextStyle {
var link: URL?
if let url = URL(string: stringLink ) {
link = url
}
return TextStyle(
font: font,
color: color,
backgroundColor: backgroundColor,
strikethrough: strikethrough,
underline: underline,
paragraphSpacing: paragraphSpacing,
paragraphIndent: paragraphIndent,
lineHeight: lineHeight,
letterSpacing: letterSpacing,
lineBreakMode: lineBreakMode,
alignment: alignment,
link: link
)
}
}
public extension NSAttributedString {
// MARK: - Initializers
convenience init(string: String, style: TextStyle, includingParagraphStyle: Bool = true) {
self.init(string: string, attributes: style.attributes(includingParagraphStyle: includingParagraphStyle))
}
}
public extension NSMutableAttributedString {
@discardableResult
func withSubstringStyle(substring: String, style: TextStyle, includingParagraphStyle: Bool = false) -> NSMutableAttributedString {
let range = self.mutableString.range(of: substring)
self.setAttributes(style.attributes(includingParagraphStyle: includingParagraphStyle), range: range)
return self
}
func append(_ substring: String, withStyle style: TextStyle, includingParagraphStyle: Bool = false) {
self.append(NSMutableAttributedString(string: substring, attributes: style.attributes(includingParagraphStyle: includingParagraphStyle)))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment