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)
- }
- }
0 件のコメント:
コメントを投稿