2015/06/17

Swiftでテキスト内リンク&テキストタップ検出


指定したテキスト内にリンクを設定したいことがあります。
@you_matz #swiftなどをリンクとして埋め込みたい場合
そしてそのリンクをタップした際に別の画面に遷移させるなど。

実現方法

①UITextViewのプロパティの設定

textView.userInteractionEnabled = true
textView.editable = false

// tapでテキストのポジション検出可能とするため
textView.selectable = true

// 行間レイアウト用
// textView.layoutManager.delegate = self

②テキスト内リンク範囲指定

let text = "Swiftでテキスト内リンク&テキストタップ検出"
let linkText = "リンク"
let nsTex = text as NSString
let link = text.rangeOfString(linkText)
let attributedString = NSMutableAttributedString(string: text)
let start = distance(text.startIndex, link!.startIndex)
let length = distance(link!.startIndex, link!.endIndex)

// リンク位置範囲生成
range = NSMakeRange(start, length)

③textviewに指定した色、カラー、下線を指定後、代入

// テキスト全体文字色
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.whiteColor(), range: NSMakeRange(0, nsTex.length))

// リンクカラー
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.blueColor(), range: range)

// リンク下線
attributedString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: range)
// 属性を代入
textView.attributedText = attributedString

④textViewにgesture追加

// gesture追加
let tap = UITapGestureRecognizer(target: self, action: "tapText:")
textView.addGestureRecognizer(tap)

⑤tap時の動作

func tapText(tap: UITapGestureRecognizer) {

    // タップされた座標をもとに最寄りの文字列の位置を取得
    let location = tap.locationInView(textView)
    let textPosition = textView.closestPositionToPoint(location)

    // テキストの先頭とタップした文字の距離をNSIntegerで取得
    let selectedPosition = firstTextView.offsetFromPosition(firstTextView.beginningOfDocument, toPosition: textPosition!)

    // タップした文字がリンク文字のrangeに含まれるか判定
    if NSLocationInRange(selectedPosition, range) {

        // リンクタップ時の処理
        // let webVC = WebViewController()
        // self.presentViewController(webVC, animated: true, completion: nil)    
    }
}

参考

NSAttributedStringを使ってリンク文字を作る(Objective-C)
https://gist.github.com/yoshimin/858d14751fc1c00807d2
UITextView でタップ可能なリンクをカスタマイズする
http://kishikawakatsumi.hatenablog.com/entry/20130605/1370370925