TTTAttributedLabel は UILabel の代わりに利用できる, リンクの検出などの機能を備えたライブラリです. この記事では TTTAttributedLabel で表示しているリンクを iPhone 6s / 6s Plus で利用できる 3D Touch の機能の一つである Peek & Pop に対応させる方法を紹介します.
目標
この記事ではある ViewController の subview として TTTAttributedLabel を持ち, この TTTAttributedLabel の中に表示されているリンクを Peek & Pop に対応させる方法を紹介します.
動作のイメージ (Tweetbot 4 より):
(※Tweetbot 4 が TTTAttributedLabel を利用しているかどうかは分かりません)
TTTAttributedLabel を subview として配置させる方法や, TTTAttributedLabel でリンクを検出して表示する方法などはこの記事の対象外です.
TTTAttributedLabel
現在リリースされている1.13.4 は Peek & Pop に対応するために便利なメソッド linkAtPoint が実装されていません. c9d9219 で実装されているので, これ以降のバージョンを Git で取得して利用してください.
2016/5/14 更新: 2016/5 にリリースされた 2.0.0 で -[TTTAttributedLabel linkAtPoint:] が公開されました. 2.0.0 以降のバージョンを用いることで, 以下の手順に従って 3D Touch 対応を行えます.
viewDidLoad
Peek & Pop に対応するには registerForPreviewingWithDelegate:sourceView: を用いて, Peek & Pop を利用するビューを登録しておきます. ここでは UIViewController の view を登録します.
override func viewDidLoad() {
// 省略
if traitCollection.forceTouchCapability == .Available {
registerForPreviewingWithDelegate(self, sourceView: view)
}
}
UIViewControllerPreviewingDelegate
Peek & Pop に対応するには ViewController を UIViewControllerPreviewingDelegate に適合させます. サンプルコードは次のようになります.
extension ViewController: UIViewControllerPreviewingDelegate {
func previewingContext(previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
let point = previewingContext.sourceView.convertPoint(location, toView: label)
guard label.containslinkAtPoint(point) else { return nil }
guard let link = label.linkAtPoint(point),
url = link.result.URL else { return nil }
// previewingContext.sourceRect をよしなに設定する
let safariViewController = SFSafariViewController(URL: url)
return safariViewController
}
func previewingContext(previewingContext: UIViewControllerPreviewing, commitViewController viewControllerToCommit: UIViewController) {
presentViewController(viewControllerToCommit, animated: true, completion: nil)
}
}
2行目の previewingContext:viewControllerForLocation: は Peek する際に呼び出されるメソッドです. location の場所にあるビューが Peek に対応しているのであれば, Peek する ViewController を返し, Peek に対応していないのであれば nil を返します. このメソッドには次のような処理が実装されています (label を TTTAttributedLabel とします):
- 3行目で選択された座標を
label上の座標に変換します - 4行目で選択された座標がリンクの上かどうかを判定します
- 5行目で選択された座標に対応するリンク (TTTAttributedLabelLink) を取得します
- 6行目でリンクから URL を取得します
- 8,9行目で URL を SFSafariViewController で開きます
previewingContext:viewControllerForLocation: では previewingContext.sourceRect に選択されているビューの CGRect を指定することで, 指定した CGRect の範囲以外にブラーがかけられます. しかし, リンクの形は必ずしも長方形とは限らないため, ラベル全体を sourceRect に設定するなど適当な対応が必要になります.
12-14行目の previewingContext:viewControllerForLocation: は Pop する際に呼ばれる処理です. 通常は Peek 時の ViewController をそのまま表示するので, viewControllerToCommit へ遷移する処理を記述します.
