Ограничить количество строк для UITextview - PullRequest
63 голосов
/ 08 марта 2011

Мне было интересно, как ограничить количество ЛИНИЙ (не символов, которые задаются в других вопросах), которые пользователь может вводить при редактировании UITextField.

В идеале, я хотел бы ограничить ввод макс.10 строк.

С чего бы мне начать?Я делаю это с помощью метода?В

 - (BOOL)textViewShouldBeginEditing:(UITextView *)aTextView

Ответы [ 9 ]

199 голосов
/ 06 января 2015

Maciek Czarnik ответ не работает для меня, но он дал мне понимание того, что делать.

iOS 7 +

Swift

textView.textContainer.maximumNumberOfLines = 10
textView.textContainer.lineBreakMode = .byTruncatingTail

ObjC

textView.textContainer.maximumNumberOfLines = 10;
textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
51 голосов
/ 16 января 2014

Может быть, это может помочь (iOS 7 +):

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

Даже первая строка должна помочь, но не ... Может быть, это ошибка в SDK

15 голосов
/ 08 марта 2011

У вас правильная идея, но неправильный метод.textView:shouldChangeTextInRange:replacementText: вызывается всякий раз, когда текст собирается измениться;вы можете получить доступ к текущему содержимому текстового представления, используя его свойство text, и вы можете создать новое содержимое из переданного диапазона и заменить текст на [textView.text stringByReplacingCharactersInRange:range withString:replacementText].Затем вы можете подсчитать количество строк и вернуть ДА, чтобы разрешить изменение, или НЕТ, чтобы отклонить его.

12 голосов
/ 02 апреля 2014

Maciek Czarnik не отвечает мне, даже в iOS7. Это вызывает у меня странное поведение, я не знаю почему.

Чтобы ограничить количество строк в UITextView, я просто делаю:

(протестировано только в iOS7) В следующем методе UITextViewDelegate:

- (void)textViewDidChange:(UITextView *)textView
{
    NSUInteger maxNumberOfLines = 5;
    NSUInteger numLines = textView.contentSize.height/textView.font.lineHeight;
    if (numLines > maxNumberOfLines)
    {
        textView.text = [textView.text substringToIndex:textView.text.length - 1];
    }
}
11 голосов
/ 04 января 2017

в Swift 3.0 версия:

self.textView.textContainer.maximumNumberOfLines = self.textViewNumberOflines
self.textView.textContainer.lineBreakMode = .byTruncatingTail
4 голосов
/ 06 декабря 2017

Вот улучшенная версия ответа Numereyes в Swift 4

Я сделал небольшое расширение, чтобы я мог повторно использовать код.Я использую цикл while, чтобы проверить, подходит ли размер.Это также работает, когда пользователь вставляет много текста одновременно.

extension UITextView {        
    var numberOfCurrentlyDisplayedLines: Int {
        let size = systemLayoutSizeFitting(UILayoutFittingCompressedSize)
        //for Swift 4.2, replace with next line:
        //let size = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)

        return Int(((size.height - layoutMargins.top - layoutMargins.bottom) / font!.lineHeight))
    }

    /// Removes last characters until the given max. number of lines is reached
    func removeTextUntilSatisfying(maxNumberOfLines: Int) {
        while numberOfCurrentlyDisplayedLines > (maxNumberOfLines) {
            text = String(text.dropLast())
            layoutIfNeeded()
        }
    }
}

// Use it in UITextView's delegate method:
func textViewDidChange(_ textView: UITextView) {        
    textView.removeTextUntilSatisfying(maxNumberOfLines: 10)
}        
2 голосов
/ 28 августа 2017

Другие приведенные решения не решают проблему, связанную с созданием последней строки в конце (11-я строка в случае вопроса).

Вот рабочее решение с Swift 4.0 и бета-версией Xcode 9.0 (можно найти в этом сообщении в блоге )

   class ViewController: UIViewController, UITextViewDelegate {

      @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
        textView.textContainer.maximumNumberOfLines = 10
        textView.textContainer.lineBreakMode = .byWordWrapping
      }

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

        let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
        let newLines = text.components(separatedBy: CharacterSet.newlines)
        let linesAfterChange = existingLines.count + newLines.count - 1

        return linesAfterChange <= textView.textContainer.maximumNumberOfLines
    }

Примечание: Это решение не поддерживает сценарий, в котором последняя строка слишком длинна для отображения (текст будет скрыт в правой части UITextView).

1 голос
/ 20 ноября 2017

Аналогично другим ответам, но может использоваться непосредственно из раскадровки и без подклассов:

extension UITextView {
    @IBInspectable var maxNumberOfLines: NSInteger {
        set {
            textContainer.maximumNumberOfLines = maxNumberOfLines
        }
        get {
            return textContainer.maximumNumberOfLines
        }
    }
    @IBInspectable var lineBreakByTruncatingTail: Bool {
        set {
            if lineBreakByTruncatingTail {
                textContainer.lineBreakMode = .byTruncatingTail
            }
        }
        get {
            return textContainer.lineBreakMode == .byTruncatingTail
        }
    }
}
0 голосов
/ 28 февраля 2019

для swift 4, этот работает без ошибок:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
    let newLines = text.components(separatedBy: CharacterSet.newlines)
    let linesAfterChange = existingLines.count + newLines.count - 1
    return linesAfterChange <= textView.textContainer.maximumNumberOfLines
}

, и если вы хотите ограничить символы также:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
        let newLines = text.components(separatedBy: CharacterSet.newlines)
        let linesAfterChange = existingLines.count + newLines.count - 1
        if(text == "\n") {
            return linesAfterChange <= textView.textContainer.maximumNumberOfLines
        }

        let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
        let numberOfChars = newText.count
        return numberOfChars <= 30 // 30 characters limit
    }
}

не забудьте добавить, сколько строкВы хотите, чтобы лимит был в viewDidLoad:

txtView.textContainer.maximumNumberOfLines = 2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...