- 使用插值构建富文本 流畅的编码体验 优雅自然的样式设置.
- 丰富的控件扩展支持.
- 支持多层富文本嵌套并提供嵌套样式优先级策略.
- 支持全部
NSAttributedString.Key
特性. - 支持 iOS & macOS & watchOS & tvOS.
- 支持文本和附件点击或长按事件回调, 支持高亮样式.
- 支持异步图片附件, 可以将远程图片资源加载到
UITextView
中. - 支持视图附件, 可以将自定义视图通过富文本添加到
UITextView
中. - 更多新特性的不断加入.
pod 'AttributedString'
github "lixiang1994/AttributedString"
选择 Xcode 菜单 File > Swift Packages > Add Package Dependency
输入仓库地址.
Repository: https://github.com/lixiang1994/AttributedString
将以下内容添加到你的 Package.swift
:
.package(url: "https://github.com/lixiang1994/AttributedString.git", from: "version")
首先导入
import AttributedString
初始化
// 常规初始化
let a: ASAttributedString = .init("lee", .font(.systemFont(ofSize: 13)))
// 插值初始化
let b: ASAttributedString = "\("lee", .font(.systemFont(ofSize: 13)))"
下面是一些简单示例. 支持所有设备和模拟器:
textView.attributed.text = """
\("fontSize: 13", .font(.systemFont(ofSize: 13)))
\("fontSize: 20", .font(.systemFont(ofSize: 20)))
\("fontSize: 22 weight: semibold", .font(.systemFont(ofSize: 22, weight: .semibold)))
"""
textView.attributed.text = """
\("foregroundColor", .foreground(.white))
\("foregroundColor", .foreground(.red))
"""
textView.attributed.text = """
\("strikethrough: single", .strikethrough(.single))
\("strikethrough: double color: .red", .strikethrough(.double, color: .red))
"""
// ASAttributedString.Attachment
textView.attributed.text = """
\(.data(xxxx, type: "zip"))
\(.file(try!.init(url: .init(fileURLWithPath: "xxxxx"), options: [])))
\(.attachment(NSTextAttachment()))
"""
// ASAttributedString.ImageAttachment
textView.attributed.text = """
\(.image(UIImage(named: "xxxx")))
\(.image(UIImage(named: "xxxx"), .custom(size: .init(width: 200, height: 200))))
\(.image(UIImage(named: "xxxx"), .proposed(.center))).
"""
// ASAttributedString.AsyncImageAttachment
textView.attributed.text = """
\(.image(url, placeholder: xxxxx))
"""
自定义加载器 例如使用Kingfisher加载图片, 默认加载器使用的是URLSession:
ASAttributedString.AsyncImageAttachment.Loader = AsyncImageAttachmentKingfisherLoader.self
具体细节请查看Demo中AttachmentViewController.swift
文件.
// ASAttributedString.ViewAttachment
textView.attributed.text = """
\(.view(xxxxView))
\(.view(xxxxView, .custom(size: .init(width: 200, height: 200))))
\(.view(xxxxView, .proposed(.center))).
"""
let a: ASAttributedString = .init("123", .background(.blue))
let b: ASAttributedString = .init("456", .background(.red))
textView.attributed.text = "\(wrap: a) \(wrap: b, .paragraph(.alignment(.center)))"
// 默认为嵌入模式, 嵌套的内部样式优先于外部样式
textView.attributed.text = "\(wrap: a, .paragraph(.alignment(.center)))"
textView.attributed.text = "\(wrap: .embedding(a), .paragraph(.alignment(.center)))"
// 覆盖模式, 嵌套的外部样式优先于内部样式
textView.attributed.text = "\(wrap: .override(a), .paragraph(.alignment(.center)))"
let a: ASAttributedString = .init("123", .background(.blue))
let b: ASAttributedString = .init("456", .background(.red))
let c: ASAttributedString = .init("789", .background(.gray))
textView.attributed.text = a + b
textView.attributed.text += c
var string: ASAttributedString = .init("我的电话号码是+86 18611401994.", .background(.blue))
string.add(attributes: [.foreground(color)], checkings: [.phoneNumber])
textView.attributed.text = string
var string: ASAttributedString = .init("打开 https://www.apple.com 和 https://github.com/lixiang1994/AttributedString", .background(.blue))
string.add(attributes: [.foreground(color)], checkings: [.link])
textView.attributed.text = string
var string: ASAttributedString = .init("123456789", .background(.blue))
string.add(attributes: [.foreground(color)], checkings: [.regex("[0-6]")])
textView.attributed.text = string
对于复杂的样式, 推荐优先使用 UITextView.
UITextView 需要将 isEditable
和 isSelectable
属性设置为 false
.
// 文本
let a: ASAttributedString = .init("lee", .action({ }))
// 附件 (图片)
let b: ASAttributedString = .init(.image(image), action: {
// code
})
// 建议使用函数作为参数 语法上比直接使用闭包更加整洁.
func clicked() {
// code
}
// 正常初始化
let c: ASAttributedString = .init("lee", .action(clicked))
let d: ASAttributedString = .init(.image(image), action: clicked)
// 字面量初始化
let e: ASAttributedString = "\("lee", .action(clicked))"
let f: ASAttributedString = "\(.image(image), action: clicked)"
// 获取更多信息
func clicked(_ result: ASAttributedString.Action.Result) {
switch result.content {
case .string(let value):
print("点击了文本: \(value) range: \(result.range)")
case .attachment(let value):
print("点击了附件: \(value) range: \(result.range)")
}
}
label.attributed.text = "This is \("Label", .font(.systemFont(ofSize: 20)), .action(clicked))"
textView.attributed.text = "This is a picture \(.image(image, .custom(size: .init(width: 100, height: 100))), action: clicked) Displayed in custom size."
func pressed(_ result: ASAttributedString.Action.Result) {
switch result.content {
case .string(let value):
print("按住了文本: \(value) range: \(result.range)")
case .attachment(let value):
print("按住了附件: \(value) range: \(result.range)")
}
}
label.attributed.text = "This is \("Long Press", .font(.systemFont(ofSize: 20)), .action(.press, pressed))"
textView.attributed.text = "This is a picture \(.image(image, .custom(size: .init(width: 100, height: 100))), trigger: .press, action: pressed) Displayed in custom size."
func clicked(_ result: ASAttributedString.Action.Result) {
switch result.content {
case .string(let value):
print("点击了文本: \(value) range: \(result.range)")
case .attachment(let value):
print("点击了附件: \(value) range: \(result.range)")
}
}
label.attributed.text = "This is \("Label", .font(.systemFont(ofSize: 20)), .action([.foreground(.blue)], clicked))"
// 触发方式为 按住, 高亮样式为 蓝色背景色和白色文字
let custom = ASAttributedString.Action(.press, highlights: [.background(.blue), .foreground(.white)]) { (result) in
switch result.content {
case .string(let value):
print("按住了文本: \(value) range: \(result.range)")
case .attachment(let value):
print("按住了附件: \(value) range: \(result.range)")
}
}
label.attributed.text = "This is \("Custom", .font(.systemFont(ofSize: 20)), .action(custom))"
textView.attributed.text = "This is a picture \(.image(image, .original(.center)), action: custom) Displayed in original size."
// 监听 电话号码类型的点击事件 并设置点击时高亮样式为蓝色字体
label.attributed.observe([.phoneNumber], highlights: [.foreground(.blue)]) { (result) in
print("当前点击了 \(result)")
}
// 监听 链接和时间类型的点击事件 并设置点击时高亮样式为蓝色字体
textView.attributed.observe([.link, .date], highlights: [.foreground(.blue)]) { (result) in
print("当前点击了 \(result)")
}
更多示例请查看工程应用.
以下属性可用:
属性 | 类型 | 描述 |
---|---|---|
font | UIFont |
字体 |
color | UIColor |
字色 |
background | UIColor |
背景色 |
paragraph | ParagraphStyle |
段落样式 |
ligature | Bool |
连体字 |
kern | CGFloat |
字间距 |
strikethrough | NSUnderlineStyle . UIColor |
删除线样式与颜色 (如果颜色为空 则和字色一致) |
underline | NSUnderlineStyle , UIColor |
下划线样式与颜色 (如果颜色为空 则和字色一致) |
link | String / URL |
链接 |
baselineOffset | CGFloat |
基准线偏移 |
shadow | NSShadow |
阴影 |
stroke | CGFloat , UIColor |
描线宽度与颜色 |
textEffect | NSAttributedString.TextEffectStyle |
文本效果 |
obliqueness | CGFloat |
斜体 |
expansion | CGFloat |
拉伸/压缩 |
writingDirection | WritingDirection / [Int] |
书写方式 |
verticalGlyphForm | Bool |
垂直排版 (当前在iOS上, 它始终是水平的) |
CASE | 描述 |
---|---|
range(NSRange) |
自定义范围 |
regex(String) |
正则表达式 |
action |
动作 |
date |
时间 (基于NSDataDetector ) |
link |
链接 (基于NSDataDetector ) |
address |
地址 (基于NSDataDetector ) |
phoneNumber |
电话 (基于NSDataDetector ) |
transitInformation |
航班 (基于NSDataDetector ) |
如果您需要实现特定功能或遇到错误,请打开issue。 如果您自己扩展了AttributedString的功能并希望其他人也使用它,请提交拉取请求。
AttributedString 使用 MIT 协议. 有关更多信息,请参阅LICENSE文件.