Обнаруживать момент запуска новой строки в UITextView

Я пытаюсь обнаружить, когда каретка идет по новой строке в UITextView. Я могу обнаружить его путем сравнения общей ширины позже с шириной UITextView:

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

Но доза не работает должным образом, потому что -sizeWithAttributes:textView возвращает только ширину букв без ширины отступа. Помогите решить эту проблему.

Ответ 1

Вот как я бы это сделал:

  • Получить UITextPosition последнего символа.
  • Вызовите caretRectForPosition для вашего UITextView.
  • Создайте переменную CGRect и изначально сохраните в ней CGRectZero.
  • В вашем textViewDidChange: метод вызовите caretRectForPosition: путем передачи UITextPosition.
  • Сравните его с текущим значением, хранящимся в переменной CGRect. Если новый y-источник элемента caretRect больше последнего, это означает, что достигнута новая строка.

Образец кода:

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 протокол UITextInput здесь. Это волшебно, я говорю вам.

Дайте мне знать, если у вас есть другие проблемы с этим.

Ответ 2

Для 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

    }

Ответ 3

ответ @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
    }

Ответ 4

Swift 3

Принятый ответ и быстрая версия работают нормально, но вот версия 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
    }
}

Ответ 5

Вы можете использовать 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;
}

Ответ 6

Вам нужно получить высоту текста, а не ширину. Используйте либо sizeWithFont:constrainedToSize:lineBreakMode: (если вам нужно поддерживать iOS 6 или ранее), либо используйте boundingRectWithSize:options:attributes:context:, если вы поддерживаете только iOS 7.

Ответ 7

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
    }
}