-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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