LoginSignup
115
84

More than 5 years have passed since last update.

Swift 5で進化するNSAttributedStringの扱い方

Last updated at Posted at 2019-04-08

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をラップしたものを作りました。

AttributedString.swift
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にもおいておくので色々試してみてください!

115
84
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
115
84