如何在(有时)可编辑的 UITextView 中启用数据检测器
Posted
技术标签:
【中文标题】如何在(有时)可编辑的 UITextView 中启用数据检测器【英文标题】:How to enable Data Detectors in a (sometimes-) editable UITextView 【发布时间】:2010-10-10 15:14:26 【问题描述】:有谁知道内置的 Notes 应用程序如何设法显示数据检测器,但它的 UITextView 仍可编辑?
我尝试将可编辑默认设置为 NO(因此数据检测器将起作用),然后覆盖 UITextView 的触摸方法并将其设置为 YES,但它最终会滚动到底部,我必须再次点击才能真正开始编辑。
我也尝试过使用轻击手势识别器,同样的事情发生了。我正在尝试查看正在运行的触摸事件并将可编辑设置为“是”,以便 UITextView 将在点击点开始编辑但没有骰子 - 如果我无法让它将触摸事件传递给 UITextView弄乱了它的可编辑属性。
【问题讨论】:
什么是数据检测器?我正在查看我 iphone 上的 Notes 应用程序,但我不知道您指的是什么。 数据检测器是电话号码、地址、URL 等的自动链接。 【参考方案1】:一个简单的技巧是在 textview 上放置一个透明视图,以拦截触摸事件。当有人按下透明度时,将 textview 设置为可编辑并使其成为第一响应者,以便键盘显示。
然后,当您退出键盘的第一响应者状态(即用户已完成编辑)时,将可编辑标志设置回 NO。
[编辑]
查找字符串的大小,以便确定将触摸/光标映射到的位置。使用这个:
CGSize *sizeOfString = [YourString sizeWithFont:[UIFont systemFontOfSize:yourTextViewFontSize]
constrainedToSize:CGSizeMake(widthOfYourTextView,
heightOfYourTextView)
lineBreakMode:UILineBreakModeWordWrap];
[编辑 x2] 你试过把两个文本视图放在一起吗?一个在启用数据检测器的情况下不可编辑,另一个可编辑但 alpha 为 0.0。当文本在一个中更改时,将文本复制到另一个。
【讨论】:
谢谢。我在父视图(UIViewController 的视图)上尝试了与 UITapGestureRecognizer 类似的东西。问题是,一旦您将 UITextView 的可编辑属性设置为 YES,它就会使 UITextView 成为第一响应者,但也会将插入点移动到文本的底部 - 我需要它留在用户点击的位置。 你不能也以编程方式设置 selectedRange。即 NSMakeRange(indexOfWhereYouWantCursor, 0);您必须大致弄清楚他们接触的位置,其中有多少个字符。 我也试过了,但我不知道如何将触摸位置映射到选择范围。 谢谢安德鲁。我之前半考虑过双重文本视图,但不以为然。不过它可能会起作用。我会试一试的。也感谢字符串大小技巧 - 看起来它会派上用场。【参考方案2】:只需创建一个 UITextView 子类,并像这样覆盖func touchesEnded(_:with:)
(在 Swift 4 中):
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?)
super.touchesEnded(touches, with: event)
// Only triggered when not in editing mode.
if !isEditable
// Turning off editable will make the data detectors available.
// (I set my data detectors in Interface Builder)
isEditable = true
// Retreive the insert point from touch.
guard let location = touches.first?.location(in: self) else fatalError()
guard let position = closestPosition(to: location) else fatalError()
guard let range: UITextRange = self.textRange(from: position, to: position) else fatalError()
// You will want to make the text view enter editing mode by one tap, not two.
becomeFirstResponder()
// Set the insert point.
selectedTextRange = range
由于点击链接或选择字符串时不会调用此函数,因此它适用于数据检测器。
要使数据检测器再次工作,只需将isEditable
设置为false
,可能在委托对象中:
func textViewDidEndEditing(_ textView: UITextView)
textView.isEditable = false
关键在于从触摸转动插入点。
【讨论】:
除非我遗漏了什么,否则这似乎不起作用。在 ios13、xcode 11 上,不会触发 url 并且 textView 进入编辑模式,无论触摸是否在 url 上。 @FinniusFrog 抱歉耽搁了。我发布了一个我使用的可行解决方案。希望能帮助到你。如果您发现任何可以改进的地方,请告诉我。【参考方案3】:我可以通过将 yesleon 的答案和answer 结合在一起来实现这一点。我确信它可以改进,但它对我来说是可行的。
下面的代码是我的ListItemTextView
类的一部分,它继承自UITextView
。
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?)
super.touchesEnded(touches, with: event)
guard let touchPoint = touches.first?.location(in: self) else fatalError()
let glyphIndex = self.layoutManager.glyphIndex(for: touchPoint, in: self.textContainer)
let glyphRect = self.layoutManager.boundingRect(forGlyphRange: NSRange(location: glyphIndex, length: 1), in: self.textContainer)
if glyphIndex < self.textStorage.length,
glyphRect.contains(touchPoint),
self.textStorage.attribute(NSAttributedString.Key.link, at: glyphIndex, effectiveRange: nil) != nil
// Then touchEnded on url
return
else
isEditable = true
// Retreive the insert point from touch.
guard let position = closestPosition(to: touchPoint) else fatalError()
guard let range: UITextRange = self.textRange(from: position, to: position) else fatalError()
// You will want to make the text view enter editing mode by one tap, not two.
becomeFirstResponder()
// Set the insert point.
selectedTextRange = range
【讨论】:
以上是关于如何在(有时)可编辑的 UITextView 中启用数据检测器的主要内容,如果未能解决你的问题,请参考以下文章
UIAlertController 内的多行可编辑文本 UITextview?
UIAlertController中的多行可编辑文本UITextview?
iOS UIAlertview 与 uitextview 可编辑
选择另一个 UITextView 时,如何阻止 UITextView 退出第一响应者/关闭键盘?