本文提供兩種簡(jiǎn)單的AttributedString的生成方式
??iOS中的NSAttributedString一直覺(jué)得不太好用,每次要加一個(gè)稍微復(fù)雜點(diǎn)的特征字符串就很麻煩,你可能會(huì)看到這樣的代碼
let attrS = NSMutableAttributedString(string: "回憶是抓不到的月光,")
let att1 = NSAttributedString(string: "握緊就變黑暗", attributes: [.font: UIFont.systemFont(ofSize: 20), .foregroundColor: UIColor.red ])
attrS.append(att1)
attrS.append(NSAttributedString(string: ",讓虛假的背影消失于晴朗,陽(yáng)光在"))
let attch = NSTextAttachment()
attch.image = UIImage(named: "Lock")
attch.bounds = CGRect(x: 0, y: -20, width: 50, height: 50)
attrS.append(NSAttributedString(attachment: attch))
attrS.append(NSAttributedString(string: "身上流轉(zhuǎn),等所有業(yè)障被原諒"))
創(chuàng)建一個(gè)不太復(fù)雜的字符串就需要很長(zhǎng)的代碼,而且不是很直觀。
一、為NSMutableAttributedString加拓展的方式
??為了解決這個(gè)問(wèn)題,筆者試用鏈?zhǔn)秸Z(yǔ)法的方式對(duì)NSMutableAttributedString做了一個(gè)拓展,同時(shí)創(chuàng)建了一個(gè)Attributes的類(lèi)??梢允褂面?zhǔn)秸Z(yǔ)法加閉包的方式快速簡(jiǎn)單的實(shí)現(xiàn)AttributedString,用了之后會(huì)再也回不去。
這里舉個(gè)栗子,簡(jiǎn)單的方式就可以實(shí)現(xiàn)上述同樣的方式。而且一些重復(fù)的工作一句就搞定
let attr = NSMutableAttributedString()
attr.add("回憶是抓不到的月光,")
.add("握緊就變黑暗") {$0.font(20).color(.red)}
.add(",讓虛假的背影消失于晴朗,陽(yáng)光在")
.addImage("Lock", CGRect(x: 0, y: -20, width: 50, height: 50))
.add("身上流轉(zhuǎn),等所有業(yè)障被原諒")
.add {$0.color(.blue)}//此方法只對(duì)整個(gè)字符串沒(méi)有加color特征的部分生效
主要方法下三個(gè)
/// 添加字符串并為此段添加對(duì)應(yīng)的Attribute
/// - Parameters:
/// - text: 要添加的String
/// - arrtibutes: Attribute特征
/// - Returns: self
@discardableResult
func add(_ text: String, arrtibutes: ((inout Attributes) -> ())? = nil) -> NSMutableAttributedString {
var arrtibute = Attributes()
arrtibutes?(&arrtibute)
let arrStr = NSMutableAttributedString(string: text, attributes: arrtibute.attributes)
append(arrStr)
return self
}
/// 添加Attribute作用于當(dāng)前整體字符串,如果不包含傳入的attribute,則增加當(dāng)前特征
/// - Parameter arrtibutes: Attribute的DIc
@discardableResult
func add(arrtibutes: (inout Attributes) -> ()) -> NSMutableAttributedString {
let range = NSRange(string.startIndex..<string.endIndex, in: string)
var attribute = Attributes()
arrtibutes(&attribute)
enumerateAttributes(in: range, options: .reverse) { (oldAttribute, range, _) in
var newAtt = oldAttribute
attribute.attributes.forEach { (newkey, value) in
if !oldAttribute.keys.contains(newkey) {
newAtt[newkey] = value
}
}
addAttributes(newAtt, range: range)
}
return self
}
/// 為AttributeString添加圖片
/// - Parameters:
/// - name: 圖片名字
/// - bounds: 圖片的bounds
/// - Returns: self
@discardableResult
func addImage(_ name: String, _ bounds: CGRect) -> NSMutableAttributedString {
let attch = NSTextAttachment()
attch.image = UIImage(named: name)
attch.bounds = bounds
let attchAttri = NSAttributedString(attachment: attch)
append(attchAttri)
return self
}
??1.func add(_ text: String, arrtibutes: ((inout Attributes) -> ())? = nil) -> NSMutableAttributedString
此方法為基礎(chǔ)方法,添加字符串同時(shí)增加Attributes,對(duì)本段字符串生效,這里試用參數(shù)默認(rèn)值的方式,如果只是添加字符串不加特征,可以省略閉包
??2.func add(arrtibutes: (inout Attributes) -> ()) -> NSMutableAttributedString *
我們也會(huì)遇到,一段字符串,中間幾段特殊,然后其他的特征是一樣的,這就可以使用這個(gè)方法。
該方法會(huì)對(duì)當(dāng)前整體生效(調(diào)用該方法時(shí)候的字符串,不影響后序添加的字符),對(duì)已有的屬性不影響,只會(huì)為不包含當(dāng)前屬性的添加該特征
??3.func addImage(_ name: String, _ bounds: CGRect) -> NSMutableAttributedString*
添加Image的支持
其中Attributes的類(lèi)比較簡(jiǎn)單這里就不提了,可以直接看源碼
二、使用字符串插值協(xié)議
最近又發(fā)現(xiàn)一個(gè)好玩的東西StringInterpolationProtocol,它可以讓你使用\()的方式為字符串插值
下面這種形式你應(yīng)該不陌生
let time = 10
let string = "The time is \(time)."
??使用\()的方式可以在字符串中方便的插值這個(gè)是很早就有的,而在swift5中,swift增加了StringInterpolationProtocol。這個(gè)協(xié)議允許你來(lái)以自己的方式來(lái)實(shí)現(xiàn)字符串插值。這就為特征字符串的生成方式提供了新的可能,這里不再詳細(xì)介紹協(xié)議的用法,主要說(shuō)說(shuō)如何用來(lái)做特征字符串的實(shí)現(xiàn),我們先來(lái)看結(jié)果:
//一行太長(zhǎng)這里用回車(chē)做了分隔,實(shí)際是一句代碼
let str: AttributedString = "\("回憶", .weithtFont(20, .semibold), .color(.cyan), .stroke(.blue, 3))是抓不到的月光,
\("握緊就變黑暗", .font(20), .color(.red), .paragraphStyle{$0.alignment(.center)}, .strike(.black, .double)),讓
\("虛假", .font(20), .kern(5), .obliqueness(-0.2), .color(.orange))的背影消失于
\("晴朗", .font(20), .underline(.blue, .double)),陽(yáng)光在
\(image: UIImage(named: "Lock"), bounds: CGRect(x: 0, y: -20, width: 50, height: 50))
身上流轉(zhuǎn),等所有業(yè)障被原諒"
這里AttributedString是自己創(chuàng)建的類(lèi),主要方法是下面兩個(gè)
func appendInterpolation(_ string: String, _ attributes: AttributedString.Attributes...) {
var attr = [NSAttributedString.Key : Any]()
attributes.forEach { attr.merge($0.attributes, uniquingKeysWith: {$1})}
let astr = NSAttributedString(string: string, attributes: attr)
self.attributedString.append(astr)
}
func appendInterpolation(image: UIImage?, bounds: CGRect) {
let attch = NSTextAttachment()
attch.image = image
attch.bounds = bounds
let attchAttri = NSAttributedString(attachment: attch)
self.attributedString.append(attchAttri)
}
appendInterpolation 也是這個(gè)協(xié)議中最主要的方法,每次有\(zhòng)()的時(shí)候就會(huì)走進(jìn)你定定義的方法。后面的Attributes也是自定義的新的類(lèi),用來(lái)添加Attribtue這里使用了可變形參函數(shù),可以傳入多個(gè)Attributes
具體代碼邏輯可以看這里
關(guān)于StringInterpolationProtocolSwift中有詳盡的描述和例子,可以參考代碼和文檔理解