Swift5がリリースされましたね。
Swift5にはABIの安定化やResult型のStandard Library追加など様々な追加・変更がありました。
次のURLにまとまった神Playgroundがあるので、みたことない人はおさらいしましょう。
https://github.com/twostraws/whats-new-in-swift-5-0
String Interpolationを使ってNSAttributedStringをラップする
この中でString Interpolationという機能があります。
String Interpolationの使い方は上記Playgroundを参照してください。
このString Interpolationを使うとめちゃめちゃNSAttributedStringが便利になります。
下記にNSAttributedStringをラップしたものを作りました。
import UIKit
public struct AttributedString: ExpressibleByStringLiteral, ExpressibleByStringInterpolation, CustomStringConvertible {
public struct StringInterpolation: StringInterpolationProtocol {
public var attributedString: NSMutableAttributedString
public init(literalCapacity: Int, interpolationCount: Int) {
attributedString = NSMutableAttributedString()
}
public func appendLiteral(_ literal: String) {
attributedString.append(NSAttributedString(string: literal))
}
public func appendInterpolation(_ linkText: String? = nil, URL url: URL) {
let text = linkText ?? url.absoluteString
attributedString.append(NSAttributedString(string: text, attributes: [.link: url]))
}
public func appendInterpolation(_ image: UIImage, bounds: CGRect? = nil) {
let textAttachment = NSTextAttachment()
textAttachment.image = image
if let bounds = bounds {
textAttachment.bounds = bounds
}
attributedString.append(NSAttributedString(attachment: textAttachment))
}
func appendInterpolation(_ text: String, attributes: [NSAttributedString.Key: Any]) {
attributedString.append(NSAttributedString(string: text, attributes: attributes))
}
}
public var attributedString: NSAttributedString
public init(stringLiteral value: String) {
attributedString = NSAttributedString(string: value)
}
public init(stringInterpolation: StringInterpolation) {
attributedString = NSAttributedString(attributedString: stringInterpolation.attributedString)
}
public init(attributedString: NSAttributedString) {
self.attributedString = attributedString
}
public var description: String {
return attributedString.description
}
}
このようにするとほとんど文字列と同じようにAttributedStringを作ることができます。
let attrStr: AttributedString = "新規登録は\("こちら", URL: URL(string: "http://example.com/signin")!)"
print(attrStr)
新規登録は{
}こちら{
NSLink = "http://example.com/signin";
}
Textにimageを追加するのも簡単です!
let image = UIImage(named: "sun")!
let attrStr: AttributedString = "今日はいい天気だ\(image)"
今日はいい天気だ{
}{
NSAttachment = "<NSTextAttachment: 0x60000050d490>";
}
もし自前で表現を追加したい場合はAttributedString.StringInterpolationを拡張してappendInterpolation methodを追加してください。
extension AttributedString.StringInterpolation {
// 任意のサイズのスペースを追加
public func appendInterpolation(space: CGFloat) {
let textAttachment = NSTextAttachment()
textAttachment.bounds.size.width = space
attributedString.append(NSAttributedString(attachment: textAttachment))
}
}
let attrStr: AttributedString = "ここから\(space: 100)ここまで"
UIで表示したい場合はattributedStringプロパティがあるのでそれを利用すれば表示できます。
let label = UILabel()
label.attributedText = attrStr.attributedString
label.sizeToFit()
まとめ
最初Swift5でこの機能を見たときは、ちょっと便利そうだけど使う機会あるかなと思っていました。
しかし使ってみるとかなりの神機能でNSAttributedStringをここまで進化させてくれるものとは思いませんでした。
上記AttributedString.swiftはgistにもおいておくので色々試してみてください!