¿Cómo limitar el número de líneas en UITextView?

Tengo un UITextView en mi pantalla, el usuario debe llenar solo dos líneas y cuando el usuario en la segunda línea, la key de retorno debe convertirse en Listo .

¿Cómo puedo limitar el número de líneas en UITextView? ¡Busqué mucho, y ningún resultado fue útil!

Encontré esta respuesta para Swift:

locationNoteTextView.textContainer.maximumNumberOfLines = 2 self.locationNoteTextView.textContainer.lineBreakMode = NSLineBreakMode.ByClipping 

No funcionó, de esta manera el usuario puede ingresar caracteres infinitos, ¡pero lo que se ve en la pantalla son solo dos líneas!

Entonces, si trató de imprimir el text de textView, encontrará un text de desastre.

Necesita implementar textView:shouldChangeTextInRange:replacementText: Este método se invoca cuando el text va a cambiar. Puede acceder al contenido actual de la vista de text utilizando su propiedad de text.

Construya el nuevo contenido del range aprobado y el text de reemploop con [textView.text stringByReplacingCharactersInRange:range withString:replacementText] .

A continuación, puede contar el número de líneas y devolver YES para permitir el cambio o NO para rechazarlo.

EDITAR: en la request de OP:

 func sizeOfString (string: String, constrainedToWidth width: Double, font: UIFont) -> CGSize { return (string as NSString).boundingRectWithSize(CGSize(width: width, height: DBL_MAX), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).size } func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { let newText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text) var textWidth = CGRectGetWidth(UIEdgeInsetsInsetRect(textView.frame, textView.textContainerInset)) textWidth -= 2.0 * textView.textContainer.lineFragmentPadding; let boundingRect = sizeOfString(newText, constrainedToWidth: Double(textWidth), font: textView.font!) let numberOfLines = boundingRect.height / textView.font!.lineHeight; return numberOfLines <= 2; } 

Para iOS 7 o más

 textView.textContainer.maximumNumberOfLines = 10; textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail; 

O

 textView.textContainer.maximumNumberOfLines = 10; [textView.layoutManager textContainerChangedGeometry:textView.textContainer]; 

esta es respuesta de @Abhinav pero en Swift

 func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { let newText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text) let textAttributes = [NSFontAttributeName: textView.font] var textWidth: CGFloat = CGRectGetWidth(UIEdgeInsetsInsetRect(textView.frame, textView.textContainerInset)) textWidth -= 2.0 * textView.textContainer.lineFragmentPadding let boundingRect: CGRect = newText.boundingRectWithSize(CGSizeMake(textWidth, 0), options: NSStringDrawingOptions.UsesLineFragmentOrigin|NSStringDrawingOptions.UsesFontLeading, attributes: textAttributes, context: nil) var numberOfLines = CGRectGetHeight(boundingRect) / textView.font.lineHeight; return numberOfLines <= 2; } 

En caso de que alguien quiera contar el número de línea en time real, así es como lo hace con RxSwift y RxCocoa

  let disposeBag = DisposeBag() textView.rx_text.asDriver().driveNext { text in let text = text as NSString var textWidth: CGFloat = CGRectGetWidth(UIEdgeInsetsInsetRect(self.textView.frame, self.textView.textContainerInset)) textWidth -= 2.0 * self.textView.textContainer.lineFragmentPadding let textAttributes = [NSFontAttributeName: UIFont(name: “Set your font here”, size: 26.0)!] let boundingRect: CGRect = text.boundingRectWithSize(CGSizeMake(textWidth, 0), options: [NSStringDrawingOptions.UsesLineFragmentOrigin, NSStringDrawingOptions.UsesFontLeading], attributes: textAttributes, context: nil) let font = UIFont(name: “Set your font here”, size: 26.0) guard let lineHeight = font?.lineHeight else {return} let numberOfLines = CGRectGetHeight(boundingRect) / lineHeight if numberOfLines <= 2 { self.textView.typingAttributes = [NSFontAttributeName: UIFont(name: “Set your font here”, size: 26.0)!, NSForegroundColorAttributeName: “Set your color here”] } else { self.textView.typingAttributes = [NSFontAttributeName: UIFont(name: “Set your font here”, size: 18.0)!, NSForegroundColorAttributeName: “Set your color here”] } }.addDisposableTo(disposeBag) 

Encuentre a continuación la versión del objective C de la respuesta de Abhinav:

 -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { NSString *newText = [textView.text stringByReplacingCharactersInRange:range withString:text]; CGFloat textWidth = CGRectGetWidth(UIEdgeInsetsInsetRect(textView.frame, textView.textContainerInset)); textWidth -= 2.0 * textView.textContainer.lineFragmentPadding; CGSize boundingRect = [self sizeOfString:newText constrainedToWidth:textWidth font:textView.font]; NSInteger numberOfLines = boundingRect.height / textView.font.lineHeight; return numberOfLines <= 2; } -(CGSize)sizeOfString:(NSString *)string constrainedToWidth:(double)width font:(UIFont *)font { return [string boundingRectWithSize:CGSizeMake(width, DBL_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: font} context:nil].size; }