如何在(有时)可编辑的UITextView中启用数据检测器

时间:2010-10-10 15:14:26

标签: iphone uikit ios

有没有人知道内置的Notes应用程序如何设法显示数据检测器,但仍然可以编辑其UITextView?

我已经尝试将可编辑的默认设置为NO(因此数据检测器将工作)然后覆盖UITextView的触摸方法并将其设置为YES,但它最终滚动到底部,我必须再次点击以实际开始编辑。 / p>

我还尝试使用轻敲手势识别器,同样的事情发生了。我正在尝试在飞行中看到触摸事件并将可编辑设置为YES,以便UITextView将在分接点开始编辑但没有骰子 - 如果我,我无法通过触摸事件将其传递给UITextView混乱其可编辑的财产。

3 个答案:

答案 0 :(得分:1)

一个简单的黑客就是在textview上放置一个透明视图来拦截触摸事件。当有人触及透明度时,将textview设置为可编辑,并使其成为第一个响应者,以便键盘显示。

然后当您辞退键盘的第一响应者状态(即用户完成编辑)时,将可编辑标志设置回NO。

<强> [编辑]

要查找字符串的大小,您可以找出将触摸/光标映射到的位置。使用此:

 CGSize *sizeOfString = [YourString sizeWithFont:[UIFont systemFontOfSize:yourTextViewFontSize]
                               constrainedToSize:CGSizeMake(widthOfYourTextView,
                                                            heightOfYourTextView)
                                   lineBreakMode:UILineBreakModeWordWrap];

[编辑x2] 您是否尝试过将两个文本视图放在一起?一个是数据检测器不可编辑的,另一个是可编辑的,但alpha为0.0。当文本在一个文本中更改时,将文本复制到另一个文本。

答案 1 :(得分:0)

只需创建一个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
}

关键是从触摸转动插入点。

答案 2 :(得分:0)

我能够通过结合 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
    }
}