Begrenzen Sie die Anzahl der Zeilen für UITextview


76

Ich habe mich gefragt, wie ich die Anzahl der LINES (nicht der in anderen Fragen gestellten Zeichen) begrenzen kann, die ein Benutzer beim Bearbeiten eines UITextField eingeben kann.

Idealerweise möchte ich die Eingabe auf max. 10 Zeilen.

Wo müsste ich anfangen? Mache ich das mit einer Methode? Im

 - (BOOL)textViewShouldBeginEditing:(UITextView *)aTextView

Ihre Antwort finden Sie in diesem Beitrag .
Zakaria

Antworten:


15

Sie haben die richtige Idee, aber die falsche Methode. textView:shouldChangeTextInRange:replacementText:wird aufgerufen, wenn sich der Text ändern wird; Sie können über die textEigenschaft auf den aktuellen Inhalt der Textansicht zugreifen und den neuen Inhalt aus dem übergebenen Bereich und dem Ersatztext mit erstellen [textView.text stringByReplacingCharactersInRange:range withString:replacementText]. Sie können dann die Anzahl der Zeilen zählen und JA zurückgeben, damit die Änderung abgelehnt werden kann, oder NEIN, um sie abzulehnen.


Oder meinten Sie eher Bildschirmzeilen als logische Textzeilen?
Anomie

Eigentlich ja, ich möchte Bildschirmzeilen kennen. Ich möchte eine txt-Datei in eine UITextView laden und die auf dem Bildschirm angezeigten Zeilen auf 10 oder 15 beschränken und den Rest auf dem nächsten Bildschirm anzeigen. Es ist wirklich wie ein kleines Textverarbeitungsprogramm mit einzelnen Seiten. Aus diesem Grund möchte ich die in der UITextView angezeigten Zeilen (auf dem Bildschirm) begrenzen. Aber vielleicht gibt es einen einfacheren Weg, dies zu tun? Vielleicht UIWebView verwenden?
n.evermind

1
Wenn Sie nur ausgelagertes Verhalten wünschen, beachten Sie, dass UITextViewes sich um eine Unterklasse von handelt UIScrollViewund die pagingEnabledEigenschaft auch.
Anomie

Ich denke nicht, dass dies so funktioniert, wie sollteChangeTextInRange nur die Anzahl der Zeilen vor der neuen Eingabe zählen kann. Das Hinzufügen einer Zeile für jedes Mal, wenn der neue Text "\ n" lautet, funktioniert ebenfalls nicht, da der Benutzer natürlich das Ende der Zeile erreichen könnte.
Declan McKenna

236

Die Antwort von Maciek Czarnik hat bei mir nicht funktioniert, aber sie hat mir Einblicke gegeben, was ich tun soll.

iOS 7+

Schnell

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

ObjC

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

3
Dies sollte jetzt die akzeptierte Antwort sein, auch wenn es ein paar Jahre zu spät ist, es funktioniert!
Siegfoult

34
Das ist fehlerhaft. Sie können nach dem Ende der Textansicht die Eingabetaste drücken. Dann verschwindet der Cursor und Sie müssen auf Löschen klicken, um ihn wieder zu finden.
Eric Conner

Swift 2:textView.textContainer.lineBreakMode = .ByTruncatingTail
App Dev Guy

55

Vielleicht kann dies helfen (iOS 7+):

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

Selbst die erste Zeile sollte den Trick machen, aber nicht ... Vielleicht ist es ein Fehler im SDK


12

Die Antwort von Maciek Czarnik scheint für mich selbst in iOS7 nicht zu funktionieren. Es gibt mir seltsames Verhalten, ich weiß nicht warum.

Was ich tue, um die Anzahl der Zeilen in der UITextView zu begrenzen, ist einfach:

(nur in iOS7 getestet) In der folgenden UITextViewDelegate-Methode:

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

CGSize size = [textView sizeThatFits: CGSizeMake (textView.width, MAXFLOAT)]; für mich musste ich die neue Höhe
berechnen

schöne lösung einfach und perfekt
aftab muhammed khan

11

in Swift 3.0Version:

self.textView.textContainer.maximumNumberOfLines = self.textViewNumberOflines
self.textView.textContainer.lineBreakMode = .byTruncatingTail

6

Hier ist eine verbesserte Version der Numereyes-Antwort in Swift 4.2 / Swift 5

Ich habe eine kleine Erweiterung vorgenommen, damit ich den Code wiederverwenden kann. Ich verwende eine While-Schleife, um zu überprüfen, ob die Größe passt. Dies funktioniert auch, wenn der Benutzer viel Text gleichzeitig einfügt.

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

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

4

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
}

Und wenn Sie auch Zeichen einschränken möchten:

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

Vergessen Sie nicht, die Anzahl der Zeilen hinzuzufügen, in denen sich das Limit befinden soll viewDidLoad:

txtView.textContainer.maximumNumberOfLines = 2

3

Die anderen angegebenen Lösungen lösen kein Problem im Zusammenhang mit einer letzten Zeile, die am Ende erstellt wird (eine elfte Zeile im Fall der Frage).

Hier ist eine funktionierende Lösung mit Swift 4.0& Xcode 9.0 Beta (in diesem Blog-Beitrag zu finden )

   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
    }

Hinweis: Diese Lösung behandelt nicht das Szenario, in dem die letzte Zeile zu lang ist, um angezeigt zu werden (Text wird ganz rechts in der UITextView ausgeblendet).


1

Ähnlich wie bei anderen Antworten, jedoch direkt aus dem Storyboard und ohne Unterklassen verwendbar:

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
        }
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.