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
とする必要があるのですが、
そうするとテキストが選択可能になってしまう
リンクのみタップ&選択可能にする
下記のように、.link
属性しかタップおよび選択できないようにし、
さらに、.link
属性が選択されたとしても、メニューを出さないようにすることで、
リンクだけがタップ可能な (他のテキストは選択できない) UITextView
とすることができます
リンクがタップでき、テキストは選択できない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
}
}
どや!テキスト選択できまい!
余談
別に選択できても良いとは思うけれども、
リンクがあるところのテキストだけ選択可能になっていると、ちょっとね…。