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
keine Ursache
quelle
Ihre Antwort finden Sie in diesem Beitrag .
Zakaria
Mögliches Duplikat des einschränkenden Textes in einer UITextView
Santhu

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.

Anomie
quelle
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;
Jamagas
quelle
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

Maciek Czarnik
quelle
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];
    }
}
Jon - LBAB
quelle
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
levin varghese
quelle
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)
}        
fl034
quelle
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
Ben Shabat
quelle
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).

standousset
quelle
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
        }
    }
}
Antzi
quelle