Skip to content

Instantly share code, notes, and snippets.

@xiaoxidong
Forked from davidsteppenbeck/ColorText.swift
Created May 23, 2022 08:54
Show Gist options
  • Save xiaoxidong/292eccc947cb76e171d2589bd3181c26 to your computer and use it in GitHub Desktop.
Save xiaoxidong/292eccc947cb76e171d2589bd3181c26 to your computer and use it in GitHub Desktop.
Attributed strings in Swift with color attributes [iOS 15+]. Add colors to strings in your Localizable.strings files.
import SwiftUI
struct ColorText: View {
// MARK:- Properties
/// The attributed string to display.
private let attributedString: AttributedString
var body: some View {
Text(attributedString)
}
// MARK:- Methods
/// Provides a foreground color to apply to the applicable text.
private static func color(for value: ColorAttribute.Value) -> Color {
switch value {
case .accent:
return .accentColor
case .black:
return .black
case .blue:
return .blue
case .brown:
return .brown
case .cyan:
return .cyan
case .gray:
return .gray
case .green:
return .green
case .indigo:
return .indigo
case .mint:
return .mint
case .orange:
return .orange
case .pink:
return .pink
case .purple:
return .purple
case .red:
return .red
case .teal:
return .teal
case .white:
return .white
case .yellow:
return .yellow
}
}
/// Provides an attributed string with the specified color attributes.
private static func annotateColors(from source: AttributedString) -> AttributedString {
var attrString = source
for run in attrString.runs {
guard let colorAttribute = run.color else { continue }
attrString[run.range].foregroundColor = color(for: colorAttribute)
}
return attrString
}
// MARK:- Initialization
init(withAttributedString attributedString: AttributedString) {
self.attributedString = Self.annotateColors(from: attributedString)
}
init(_ localizedKey: String.LocalizationValue) {
self.attributedString = Self.annotateColors(from: AttributedString(localized: localizedKey, including: \.color))
}
}
enum ColorAttribute: CodableAttributedStringKey, MarkdownDecodableAttributedStringKey {
enum Value: String, Codable, Hashable {
case accent
case black
case blue
case brown
case cyan
case gray
case green
case indigo
case mint
case orange
case pink
case purple
case red
case teal
case white
case yellow
}
/// This is the name that should be used to indicate the color in the string.
/// For example, "^[Hello](color: 'blue'), World!".
static var name: String = "color"
}
extension AttributeScopes {
struct ColorAttributeScope: AttributeScope {
let color: ColorAttribute
}
var color: ColorAttributeScope.Type { ColorAttributeScope.self }
}
extension AttributeDynamicLookup {
subscript<T: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeScopes.ColorAttributeScope, T>) -> T {
self[T.self]
}
}
struct ColorText_Previews: PreviewProvider {
static var previews: some View {
ColorText(withAttributedString: AttributedString(localized: "SOME_LOCALIZABLE_STRING_KEY", including: \.color))
.padding()
.background(Color(.systemBackground))
.previewLayout(.sizeThatFits)
ColorText("This is ^[colored](color: 'purple') text!")
.font(.title.bold())
.previewLayout(.sizeThatFits)
.padding()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment