Detect moment when newline starts in UITextView

18,931

Solution 1

This is how I would do it:

  • Get the UITextPosition of the last character.
  • Call caretRectForPosition on your UITextView.
  • Create a CGRect variable and initially store CGRectZero in it.
  • In your textViewDidChange: method, call caretRectForPosition: by passing the UITextPosition.
  • Compare it with the current value stored in the CGRect variable. If the new y-origin of the caretRect is greater than the last one, it means a new line has been reached.

Sample code:

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;

}

Also, you should read the documentation for UITextInput protocol reference here. It is magical, I'm telling you.

Let me know if you have any other issues with this.

Solution 2

For Swift use this

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

    }

Solution 3

answer of @n00bProgrammer in Swift-4 with more precise line break detection.

@n00bProgrammer answer is perfect except one thing it reacts differently when the user starts typing in a first line, it presents that Started New Line too.
Overcoming issue, here is the refined code

    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
    }

Solution 4

You can use the 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;
}

Solution 5

SWIFT 4

If you don't want to use previousRect. Let's try this:

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
    }
}
Share:
18,931

Related videos on Youtube

mriddi
Author by

mriddi

Updated on September 26, 2022

Comments

  • mriddi
    mriddi over 1 year

    I try to detect when carriage goes at new line in UITextView. I can detect it by comparison total later width with UITextView width:

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

    But it dose not work proper way because -sizeWithAttributes:textView returns only width of letters without indentation width. Help please solve this.

  • mriddi
    mriddi over 10 years
    Just IOS7. Plz more details about using second one
  • rmaddy
    rmaddy over 10 years
    Look at the docs. It's similar to the sizeWithAttributes: method you were using. You just need to pass in a size. Pass in a size with the desired width and a really large height. The returned size will be the same with but with the needed height to fit the text in the width.
  • n00bProgrammer
    n00bProgrammer over 10 years
    @mriddi. I have given you a skeletal structure. You will have to add conditions as per your need. For instance, editing code in the middle of your text, or replacing words or characters.
  • rmaddy
    rmaddy over 10 years
    There are cases where this won't work. What about when the user pastes in text and the caret position is moved in the process?
  • n00bProgrammer
    n00bProgrammer over 10 years
    Hence i mentioned that conditions have to be added.
  • Markus
    Markus over 8 years
    Please can anybody help me with the following question? If the user writes bulleted text (multiple line breaks) in UITextView, how to detect the total number of line breaks?
  • Nikhil Manapure
    Nikhil Manapure almost 7 years
    Will this help if textView's text is set programmatically?
  • n00bProgrammer
    n00bProgrammer almost 7 years
    @NikhilManapure, sure. Just make sure you call the relevant code after you're done setting the text. Setting text programmatically does not call the delegate method (I think, though I'm unsure).
  • JP Aquino
    JP Aquino about 6 years
    This only works if user presses return key, not if the new line starts because it reached the end of the previous line.
  • Saifan Nadaf
    Saifan Nadaf over 4 years
    in which case u get currentRect.origin.y == -1 ??