UITextView链接可选,无需其他文本可选
我正在尝试获得类似于Facebook使用的设置(如果他们使用UITextView
)。 我希望自动检测链接,但我不希望UITextView
中的任何其他文本可选。 因此,用户可以单击链接但无法选择任何其他文本。
尽管搜索过,但我还没有找到一个解决方案,因为链接选择工作需要整个文本视图可供选择。
您需要阻止UITextView
成为第一响应者。
1.将UITextView
子类化到您自己的自定义类( MyTextView
)。
2.覆盖canBecomeFirstResponder()
。 这是Swift中的一个例子:
斯威夫特3:
class MyTextView: UITextView { override func becomeFirstResponder() -> Bool { return false } }
斯威夫特2:
class MyTextView: UITextView { override func canBecomeFirstResponder() -> Bool { return false } }
检测到的任何链接仍将启用。 我用电话号码测试了这个。
你需要gestureRecognizerShouldBegin (_:)
UITextView
并覆盖gestureRecognizerShouldBegin (_:)
方法,如下所示:
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if isEditable == false { if let gesture = gestureRecognizer as? UILongPressGestureRecognizer, gesture.minimumPressDuration == 0.5 { return false } } return true }
这将阻止选择textview,但链接将按预期工作
编辑:事实certificate,当双击并按住时,您仍然可以选择文字。 我发现它发生在两次点击之后(不是具有属性“minimalNumberOfTaps”的UITapGesture,而是一个接一个地进行不同的点击),因此解决方案是在第一步之后跟踪时间(大约0.7秒)完整代码:
var lastTapTime: TimeInterval = 0 override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if isEditable == false { if let gesture = gestureRecognizer as? UILongPressGestureRecognizer, gesture.minimumPressDuration == 0.5 { return false } } if Date().timeIntervalSince1970 >= lastTapTime + 0.7 { lastTapTime = Date().timeIntervalSince1970 return true } else { return false } }
这不是最优雅的解决方案,但它似乎工作🤷♂️
所选答案在我的情况下不起作用,我不熟悉比较内部UIGestureRecognizer
内部未经证实的值。
我的解决方案是覆盖point(inside:with:)
,当用户没有触及链接文本时允许点击: https : //stackoverflow.com/a/44878203/1153630
如果您的最低部署目标是iOS 11.2或更高版本
您可以通过UITextView
并禁止可以选择某些内容的手势来禁用文本选择。
以下解决方案是:
- 与isEditable兼容
- 与isScrollEnabled兼容
- 兼容链接
/// Class to allow links but no selection. /// Basically, it disables unwanted UIGestureRecognizer from UITextView. /// https://stackoverflow.com/a/49428307/1033581 class UnselectableTappableTextView: UITextView { // required to prevent blue background selection from any situation override var selectedTextRange: UITextRange? { get { return nil } set {} } override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if gestureRecognizer is UIPanGestureRecognizer { // required for compatibility with isScrollEnabled return super.gestureRecognizerShouldBegin(gestureRecognizer) } if let tapGestureRecognizer = gestureRecognizer as? UITapGestureRecognizer, tapGestureRecognizer.numberOfTapsRequired == 1 { // required for compatibility with links return super.gestureRecognizerShouldBegin(gestureRecognizer) } // allowing smallDelayRecognizer for links // https://stackoverflow.com/questions/46143868/xcode-9-uitextview-links-no-longer-clickable if let longPressGestureRecognizer = gestureRecognizer as? UILongPressGestureRecognizer, // comparison value is used to distinguish between 0.12 (smallDelayRecognizer) and 0.5 (textSelectionForce and textLoupe) longPressGestureRecognizer.minimumPressDuration < 0.325 { return super.gestureRecognizerShouldBegin(gestureRecognizer) } // preventing selection from loupe/magnifier (_UITextSelectionForceGesture), multi tap, tap and a half, etc. gestureRecognizer.isEnabled = false return false } }
如果您的最低部署目标是iOS 11.1或更早版本
原生UITextView链接手势识别器在iOS 11.0-11.1上被破坏,需要一个小的延迟长按而不是点击 : Xcode 9 UITextView链接不再可点击
您可以使用自己的手势识别器正确支持链接,并且可以通过UITextView
并禁止可以选择内容或点击某些内容的手势来禁用文本选择。
以下解决方案将禁止选择,并且是:
- 与isScrollEnabled兼容
- 兼容链接
- iOS 11.0和iOS 11.1的解决方法限制,但在点击文本附件时会丢失UI效果
/// Class to support links and to disallow selection. /// It disables most UIGestureRecognizer from UITextView and adds a UITapGestureRecognizer. /// https://stackoverflow.com/a/49428307/1033581 class UnselectableTappableTextView: UITextView { required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) // Native UITextView links gesture recognizers are broken on iOS 11.0-11.1: // https://stackoverflow.com/questions/46143868/xcode-9-uitextview-links-no-longer-clickable // So we add our own UITapGestureRecognizer. linkGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(textTapped)) linkGestureRecognizer.numberOfTapsRequired = 1 addGestureRecognizer(linkGestureRecognizer) linkGestureRecognizer.isEnabled = true } var linkGestureRecognizer: UITapGestureRecognizer! // required to prevent blue background selection from any situation override var selectedTextRange: UITextRange? { get { return nil } set {} } override func addGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) { // Prevents drag and drop gestures, // but also prevents a crash with links on iOS 11.0 and 11.1. // https://stackoverflow.com/a/49535011/1033581 gestureRecognizer.isEnabled = false super.addGestureRecognizer(gestureRecognizer) } override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if gestureRecognizer == linkGestureRecognizer { // Supporting links correctly. return super.gestureRecognizerShouldBegin(gestureRecognizer) } if gestureRecognizer is UIPanGestureRecognizer { // Compatibility support with isScrollEnabled. return super.gestureRecognizerShouldBegin(gestureRecognizer) } // Preventing selection gestures and disabling broken links support. gestureRecognizer.isEnabled = false return false } @objc func textTapped(recognizer: UITapGestureRecognizer) { guard recognizer == linkGestureRecognizer else { return } var location = recognizer.location(in: self) location.x -= textContainerInset.left location.y -= textContainerInset.top let characterIndex = layoutManager.characterIndex(for: location, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) let characterRange = NSRange(location: characterIndex, length: 1) if let attachment = attributedText?.attribute(.attachment, at: index, effectiveRange: nil) as? NSTextAttachment { if #available(iOS 10.0, *) { _ = delegate?.textView?(self, shouldInteractWith: attachment, in: characterRange, interaction: .invokeDefaultAction) } else { _ = delegate?.textView?(self, shouldInteractWith: attachment, in: characterRange) } } if let url = attributedText?.attribute(.link, at: index, effectiveRange: nil) as? URL { if #available(iOS 10.0, *) { _ = delegate?.textView?(self, shouldInteractWith: url, in: characterRange, interaction: .invokeDefaultAction) } else { _ = delegate?.textView?(self, shouldInteractWith: url, in: characterRange) } } } }
这对我有用;
class LinkDetectingTextView: UITextView { override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if isEditable == false { if let _ = gestureRecognizer as? UITapGestureRecognizer { return false } if let longPressRecognizer = gestureRecognizer as? UILongPressGestureRecognizer, longPressRecognizer.minimumPressDuration == 0.5 { // prevent to select text but allow certain functionality in application return false } } return true } }
另外,在应用程序中将longPressGestureRecognizer的minimumPressDuration设置为另一个不同于0.5的值。
您可以将UITextView
子类UITextView
覆盖selectedTextRange
的方法,将其设置为nil 。 并且链接仍然是可点击的,但您将无法选择文本的其余部分(即使是链接,但您可以单击它)。
class CustomTextView: UITextView { override public var selectedTextRange: UITextRange? { get { return nil } set { } }