检测在 UITextView 中换行符开始的时刻



我尝试在UITextView中检测何时在换行处进行运输。我可以通过比较总后期宽度与 UITextView 宽度来检测它:

CGSize size = [textView.text sizeWithAttributes:textView.typingAttributes];
if(size.width > textView.bounds.size.width)
      NSLog (@"New line");

但它不能正常工作,因为-sizeWithAttributes:textView只返回字母宽度而没有缩进宽度。请帮忙解决这个问题。

这就是我会这样做的:

  • 获取最后一个字符的UITextPosition
  • 拨打UITextView上的caretRectForPosition
  • 创建一个CGRect变量,并最初在其中存储CGRectZero
  • textViewDidChange: 方法中,通过传递UITextPosition来调用 caretRectForPosition:
  • 将其与存储在 CGRect 变量中的当前值进行比较。如果 caretRect 的新 y 原点大于上一个原点,则表示已到达新行。

示例代码:

CGRect previousRect = CGRectZero;
- (void)textViewDidChange:(UITextView *)textView{
    UITextPosition* pos = yourTextView.endOfDocument;//explore others like beginningOfDocument if you want to customize the behaviour
    CGRect currentRect = [yourTextView caretRectForPosition:pos];
    if (currentRect.origin.y > previousRect.origin.y){
            //new line reached, write your code
        }
    previousRect = currentRect;
}

此外,您应该在此处阅读UITextInput协议参考的文档。这很神奇,我告诉你。

如果您对此有任何其他问题,请告诉我。

@n00bProgrammer Swift-4的答案,具有更精确的换行符检测。

@n00bProgrammer答案是完美的,除了一件事,当用户开始在第一行输入时,它的反应会有所不同,它也Started New Line
克服问题,这是精炼的代码

    var previousRect = CGRect.zero
    func textViewDidChange(_ textView: UITextView) {
        let pos = textView.endOfDocument
        let currentRect = textView.caretRect(for: pos)
        self.previousRect = self.previousRect.origin.y == 0.0 ? currentRect : self.previousRect
        if currentRect.origin.y > self.previousRect.origin.y {
            //new line reached, write your code
            print("Started New Line")
        }
        self.previousRect = currentRect
    }

对于 Swift,请使用这个

previousRect = CGRectZero
 func textViewDidChange(textView: UITextView) {
        var pos = textView.endOfDocument
        var currentRect = textView.caretRectForPosition(pos)
        if(currentRect.origin.y > previousRect?.origin.y){
            //new line reached, write your code
        }
        previousRect = currentRect
    }

您可以使用UITextViewDelegate

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText: (NSString *)text
{
     BOOL newLine = [text isEqualToString:@"n"];
     if(newLine)
     {
          NSLog(@"User started a new line");
     }
     return YES;
}

Swift 3

接受的答案和 swift 版本工作正常,但这里是为懒惰的人准备的 Swift 3 版本。

class CustomViewController: UIViewController, UITextViewDelegate {
    let textView = UITextView(frame: .zero)
    var previousRect = CGRect.zero
    override func viewDidLoad(){
        textView.frame = CGRect(
            x: 20, 
            y: 0, 
            width: view.frame.width, 
            height: 50
        )
        textView.delegate = self
        view.addSubview(textView)
    }
    func textViewDidChange(_ textView: UITextView) {
        let pos = textView.endOfDocument
        let currentRect = textView.caretRect(for: pos)
        if previousRect != CGRect.zero {
            if currentRect.origin.y > previousRect.origin.y {
                print("new line")
            }
        }
        previousRect = currentRect
    }
}

SWIFT 5

让我们不要把事情复杂化。

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if text == "n" {
        // return pressed
    }
}

SWIFT 4

如果您不想使用 previousRect。让我们试试这个:

func textViewDidChange(_ textView: UITextView) {
    let pos = textView.endOfDocument
    let currentRect = textView.caretRect(for: pos)
    if (currentRect.origin.y == -1 || currentRect.origin.y == CGFloat.infinity){
       print("Yeah!, I've gone to a new line") 
       //-1 for new line with a char, infinity is new line with a space
    }
}

您需要获取文本的高度,而不是宽度。使用sizeWithFont:constrainedToSize:lineBreakMode:(如果您需要支持 iOS 6 或更早版本)或使用boundingRectWithSize:options:attributes:context:(如果您仅支持 iOS 7)。

最新更新