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
へ遷移する処理を記述します.