1. リンクタップは可能である、その他のテキストは操作無反応とする
2. ダブルタップによるテキスト選択動作は不可である
3. ロングタップは不可である
UITextViewのカスタムViewを作成する
条件1から3まで満たすようなカスタムViewを作ります。この方法は、Stackoverflowに書かれているものを参考にしました。
UITextView: Disable selection, allow links
class UnselectableTextView: UITextView { override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { guard let position = closestPosition(to: point) else { return false } guard let range = tokenizer.rangeEnclosingPosition( position, with: .character, inDirection: UITextDirection(rawValue: UITextLayoutDirection.left.rawValue) ) else { return false } let startIndex = offset(from: beginningOfDocument, to: range.start) return attributedText.attribute(.link, at: startIndex, effectiveRange: nil) != nil } override func becomeFirstResponder() -> Bool { return false } }
override func point() にて、タップした位置のテキストがリンクであるかどうか判定し、override func becomeFirstResponder() にてダブルタップとロングタップを抑制しています。
ViewControllerに実装するときは、次のようになります。
class ViewController: UIViewController { @IBOutlet weak var textView: UnselectableTextView! override func viewDidLoad() { super.viewDidLoad() setupViews() } private func setupViews() { textView.delegate = self textView.isEditable = false textView.isSelectable = true textView.backgroundColor = .clear let attributedString = NSMutableAttributedString(string: "this textview has a link test.") attributedString.addAttribute(.link, value: "https://www.google.com", range: NSRange(location: 20, length: 4)) textView.attributedText = attributedString } } extension UIViewController: UITextViewDelegate { public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { print(URL.absoluteString) return false } }
ロングタップをハンドリングする
上記で作成したUnselectableTextViewに、独自の UILongPressGestureRecognizer を組み込もうとしたが断念。UITextViewの GestureRecognizer とConflictしてしまい、良い感じで実装できずでした。
代替案として、UnselectableTextViewの後ろにUIViewを配置して、このUIViewにてロングタップをハンドリングさせます。
class ViewController: UIViewController { private func setupGesture() { let longPressGesture = UILongPressGestureRecognizer( target: self, action: #selector(ViewController.longPress(_:)) ) longPressGesture.delegate = self backgroundView.addGestureRecognizer(longPressGesture) } } extension UIViewController: UIGestureRecognizerDelegate { @objc func longPress(_ sender: UILongPressGestureRecognizer) { print(sender.state.rawValue.description) } }