[Swift]でLabelの一部をリンク化させる方法


SwiftでUILabelの先頭の文字をリンク化させて見ました

UILabelで一部リンク化させたいなと思ったのですが、ライブラリを使うのは嫌なのでちょっと調べて見ました。

環境
Xcode8
Swift3

実装

class ViewController: UIViewController {

    @IBOutlet weak var helloLabel: UILabel!

    let linkText = "Hello"

    override func viewDidLoad() {
        super.viewDidLoad()

        helloLabel.isUserInteractionEnabled = true
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapGesture))
        helloLabel.addGestureRecognizer(tapGestureRecognizer)

        // リンク化させる場所を青くさせる。
        let string = helloLabel!.text!
        let range = (string as NSString).range(of: linkText)
        let attributedString = NSMutableAttributedString(string: string)
        attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.blue, range: range)
        helloLabel.attributedText = attributedString
    }

    func tapGesture(gestureRecognizer: UITapGestureRecognizer) {
        guard let text = helloLabel.text else { return }
        let touchPoint = gestureRecognizer.location(in: helloLabel)
        let textStorage = NSTextStorage(attributedString: NSAttributedString(string: linkText))
        let layoutManager = NSLayoutManager()
        textStorage.addLayoutManager(layoutManager)
        let textContainer = NSTextContainer(size: helloLabel.frame.size)
        layoutManager.addTextContainer(textContainer)
        textContainer.lineFragmentPadding = 0
        let toRange = (text as NSString).range(of: linkText)
        let glyphRange = layoutManager.glyphRange(forCharacterRange: toRange, actualCharacterRange: nil)
        let glyphRect = layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
        if glyphRect.contains(touchPoint) {
            print("Tapped")
        }
    }
}

これだけでlinkText内の任意の文字列をリンク化させることができます。

こんな感じになりました。(きもいですね)