15
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

リンクのみタップ&選択可能な UITextView

Posted at

UITextView 中の、リンクのタップ可と、テキストの選択不可を両立させる方法です!

UITextView にタップ可能なリンクを挿入すると…

リンクをタップできる`UITextView`のサンプルコード (タップで開く)
リンクをタップできるUITextView
import UIKit

class LinkTextViewController: UIViewController {
    let textView: UITextView = {
        let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
        textView.isSelectable = true
        textView.isEditable = false
        let text = "リンク集\nYahoo!\nGoogle"
        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(.font,
                                      value: UIFont.systemFont(ofSize: 32),
                                      range: NSRange.init(location: 0, length: attributedString.length))
        attributedString.addAttribute(.link,
                                      value: "https://www.yahoo.co.jp/",
                                      range: NSString(string: text).range(of: "Yahoo!"))
        attributedString.addAttribute(.link,
                                      value: "https://www.google.com/",
                                      range: NSString(string: text).range(of: "Google"))
        textView.attributedText = attributedString
        return textView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        view.addSubview(textView)
        textView.center = view.center
    }
}

extension UIViewController: UITextViewDelegate {
    public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        UIApplication.shared.open(URL)
        return false
    }
}

リンクをタップ可能にしたい場合には、isSelectable = true とする必要があるのですが、
そうするとテキストが選択可能になってしまう :scream:

Screen Shot 2019-03-10 at 21.08.36.png

リンクのみタップ&選択可能にする

下記のように、.link 属性しかタップおよび選択できないようにし、
さらに、.link 属性が選択されたとしても、メニューを出さないようにすることで、
リンクだけがタップ可能な (他のテキストは選択できない) UITextView とすることができます :smile:

リンクがタップでき、テキストは選択できないUITextView
    class MyTextView: UITextView {
        // NOTE: リンクテキストしかタップおよび選択できないようにする
        override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            guard let position = closestPosition(to: point),
                let range = tokenizer.rangeEnclosingPosition(position, with: .character, inDirection: UITextLayoutDirection.left.rawValue) else {
                    return false
            }
            let startIndex = offset(from: beginningOfDocument, to: range.start)
            return attributedText.attribute(.link, at: startIndex, effectiveRange: nil) != nil
        }

        // NOTE: テキストが選択された場合に、コピーなどのメニューを出さないようにする
        override func becomeFirstResponder() -> Bool {
            return false
        }
    }
リンクのみタップ&選択できる`UITextView`のサンプルコード (タップで開く)
import UIKit

class LinkTextViewController: UIViewController {
    class MyTextView: UITextView {
        // NOTE: リンクテキストしかタップおよび選択できないようにする
        override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            guard let position = closestPosition(to: point),
                let range = tokenizer.rangeEnclosingPosition(position, with: .character, inDirection: UITextLayoutDirection.left.rawValue) else {
                    return false
            }
            let startIndex = offset(from: beginningOfDocument, to: range.start)
            return attributedText.attribute(.link, at: startIndex, effectiveRange: nil) != nil
        }

        // NOTE: テキストが選択された場合に、コピーなどのメニューを出さないようにする
        override func becomeFirstResponder() -> Bool {
            return false
        }
    }

    let textView: MyTextView = {
        let textView = MyTextView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
        textView.isSelectable = true
        textView.isEditable = false
        let text = "リンク集\nYahoo!\nGoogle"
        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(.font,
                                      value: UIFont.systemFont(ofSize: 32),
                                      range: NSRange.init(location: 0, length: attributedString.length))
        attributedString.addAttribute(.link,
                                      value: "https://www.yahoo.co.jp/",
                                      range: NSString(string: text).range(of: "Yahoo!"))
        attributedString.addAttribute(.link,
                                      value: "https://www.google.com/",
                                      range: NSString(string: text).range(of: "Google"))
        textView.attributedText = attributedString
        return textView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        view.addSubview(textView)
        textView.center = view.center
    }
}

extension UIViewController: UITextViewDelegate {
    public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        UIApplication.shared.open(URL)
        return false
    }
}

どや!テキスト選択できまい!

Screen Shot 2019-03-10 at 21.37.50.png

余談

別に選択できても良いとは思うけれども、
リンクがあるところのテキストだけ選択可能になっていると、ちょっとね…。

参考

15
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?