SwiftUI Tips:使用 AttributedString 设置属性字符串

在 iOS 中传统处理字符串样式的方式是使用 NSAttributedString。但是因为NSAttributedString 是为 UIKit 设计的,在 SwiftUI 中使用很不方便。SwiftUI 的 Text 控件不支持 NSAttributedString,因此要在 SwiftUI 中使用 NSAttributedString,只能通过把文本包在 UILabel 里给 SwiftUI 使用(iOS 15 之前)。

如果使用需要这样通过 UIViewRepresentable:

swift 复制代码
struct UIKLabel: UIViewRepresentable {

    typealias TheUIView = UILabel
    fileprivate var configuration = { (view: TheUIView) in }

    func makeUIView(context: UIViewRepresentableContext<Self>) -> TheUIView { TheUIView() }
    func updateUIView(_ uiView: TheUIView, context: UIViewRepresentableContext<Self>) {
        configuration(uiView)
    }
}

使用的时候这样:

swift 复制代码
var body: some View {
    UIKLabel {
        $0.attributedText = NSAttributedString(string: "HelloWorld")
    }
}

所以从 iOS 15 开始,SwiftUI 的 Text 终于引入了正经的属性字符串!

Markdown!!!

如果只是常见的基础样式,直接在 Text 中使用 markdown 就可以支持。爷爷都感动的哭了。

swift 复制代码
struct ContentView: View {
    var body: some View {
        VStack {
            Text("Regular")
            Text("*Italics*")
            Text("**Bold**")
            Text("~Strikethrough~")
            Text("`Code`")
            Text("[Link](https://apple.com)")
            Text("***[They](https://apple.com) ~are~ `combinable`***")
        }
    }

这些样式可以混合在一起使用。多行的支持也和普通文本一样。

swift 复制代码
struct MultiMarkdown: View {
    var body: some View {
        Text("把**加粗**、*Italics* 全放在一起也可以的。`SwiftUI Tips Code`和[链接](https://twitter.com/bestlacklock)~不可以~可以!")
                .multilineTextAlignment(.center)
                .padding()
                .background(Color(uiColor: .secondarySystemBackground))
                .cornerRadius(16)
                .padding()
    }
}

需要说明一下,只有在 Text 中使用 markdown 修饰符才有用,如果只是传入的字符串中有符号是不会触发属性的。其实这样比较合理,否则万一有的文字带两个星号,就意外改变样式会让人很意外。如果要显示字符串中的 markdown,需要使用 AttributedString:

swift 复制代码
do {
    let thankYouString = try AttributedString(
        markdown:"**Thank you!** Please visit our [website](https://example.com)")
} catch {
    print("Couldn't parse: \(error)")
}

Attributed Strings

iOS 15 开始 Text 支持接受 AttributedString 作为参数,因此可以原生设置属性字符串了:

swift 复制代码
struct ContentView: View {
    var body: some View {
        Text(makeAttributedString())
    }
    
    func makeAttributedString() -> AttributedString {
        var string = AttributedString("Some Attributed String")
        string.foregroundColor = .blue
        return string
    }
}

使用 AttributedString 的一个重要场景就是给部分文字设置属性,AttributedString 也考虑到了这点,良好的支持 range:

swift 复制代码
struct ContentView: View {
    var body: some View {
        Text(makeAttributedString())
    }
    
    func makeAttributedString() -> AttributedString {
        var string = AttributedString("局部 红色 蓝色")
        string.foregroundColor = .blue
        
        if let range = string.range(of: "红色") {
            string[range].foregroundColor = .red
        }
        return string
    }
}

一个扩展

为了更便捷的支持常用属性字符串,我们可以直接给 Text 增加一个扩展方法。

swift 复制代码
extension Text {
    init(_ string: String, configure: ((inout AttributedString) -> Void)) {
        var attributedString = AttributedString(string) /// create an `AttributedString`
        configure(&attributedString) /// configure using the closure
        self.init(attributedString) /// initialize a `Text`
    }
}

如果是给整体设置属性这个扩展还是很实用的:

swift 复制代码
struct HandyView: View {
    var body: some View {
        VStack {
            Text("SwiftUI Tips") {
                $0.font = Font.system(size: 17, design: .monospaced)
            }
            Text("Strikethrough") {
                $0.strikethroughStyle = Text.LineStyle(pattern: .solid, color: .red)
            }
            Text("Foreground Color") {
                $0.foregroundColor = Color.purple
            }
        }
        VStack {
            Text("Kern") { $0.kern = CGFloat(10) }
            Text("Tracking") { $0.tracking = CGFloat(10) }
        }
    }
}

AttributedString | Apple Developer Documentation

iOS 15 Brings Attributed Strings to SwiftUI

相关推荐
东坡肘子5 天前
谁是 AI-relay App 的真正威胁 -- 肘子的 Swift 周报 #158
人工智能·swiftui·swift
东坡肘子12 天前
当 Build in Public 重新转入地下 -- 肘子的 Swift 周报 #157
人工智能·swiftui·swift
OliverQiu12 天前
开源一个 macOS 小工具:集中管理 ChatGPT 的网络启动配置
macos·chatgpt·swiftui·mac·proxy·codex·dmg
传奇开心果编程16 天前
【SwiftUI提高练中学】第9课 安全与隐私
swiftui·移动开发·swift·编程语言理论·开发范式·编程框架·声明式ui
传奇开心果编程17 天前
【声明式UI开发实用技术学与练】第8课 状态提升与下放
学习·flutter·react native·ui·swiftui·composer
东坡肘子17 天前
Swift Server,又多了一个 Google -- 肘子的 Swift 周报 #156
人工智能·swiftui·swift
传奇开心果编程17 天前
【现代声明式UI学与练】第4课 列表渲染与 key——如何高效渲染列表、key 的作用、列表重排时的状态保持
学习·flutter·react native·ui·swiftui·android jetpack
传奇开心果编程18 天前
【SwiftUI提高练中学】第8课 网络层架构:拦截器、重试、缓存与离线优先
学习·macos·ui·ios·swiftui
传奇开心果编程18 天前
【现代声明式UI学与练】第7课 组件通信——父传子、子传父、跨层级通信、状态提升与 Context
学习·flutter·react native·ui·swiftui·android jetpack
tink18 天前
告别 Xcode IDE:用 VS Code + SweetPad + XcodeGen 开发 iOS 应用的完整指南
ios·swiftui·xcode