Как ограничить количество строк в UITextView?

У меня есть UITextView на моем экране, пользователь должен заполнить только из двух строк, и когда пользователь во второй строке ключ возврата должен превратиться в сделал.

Как я могу ограничить количество строки в UITextView? Я много искал,и никаких результатов не было!

Я нашел этот ответ для Swift:

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

Он не работал, таким образом пользователь может ввести символ бесконечности, но то, что просматривается на экране всего две строчки!

поэтому, если вы попытаетесь распечатать текст textView, вы найдете текст бедствия.

6 ответов


нужно реализовать textView:shouldChangeTextInRange:replacementText:. Этот метод вызывается всякий раз, когда текст будет меняться. Вы можете получить доступ к текущему содержимому представления текста с помощью свойства text.

создайте новое содержимое из переданного диапазона и замените текст на [textView.text stringByReplacingCharactersInRange:range withString:replacementText].

затем вы можете подсчитать количество строк и возврата YES разрешить изменение или NO отклонить его.

EDIT: по запросу 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;
}

для iOS 7+

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

или

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

это @Abhinav ответ, но в Свифт

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

если кто-то хочет подсчитать количество строк в реальном времени, вот как вы это делаете с RxSwift & 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)

это ответ @Abhinav обновлен для Swift 3

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

    guard maxLines > 0 else {
        return true
    }

    let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)

    let textAttributes = [NSAttributedStringKey.font : textView.font!]

    var textWidth: CGFloat = UIEdgeInsetsInsetRect(textView.frame, textView.textContainerInset).width

    textWidth -= 2.0 * textView.textContainer.lineFragmentPadding

    let boundingRect: CGRect = newText.boundingRect(with: CGSize(width: textWidth, height: 0), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: textAttributes, context: nil)

    let numberOfLines = Int(floor(boundingRect.height / textView.font!.lineHeight))

    return numberOfLines <= maxLines

}

здесь maxlines, которое - это количество строк, на которое вы хотите ограничить textView. Если это 0, то неограниченное количество линий.


найдите ниже объективную версию c ответа Абхинава:

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