it-swarm.com.de

Wie kann man in UITextView Margen/Auffüllen verlieren?

Ich habe eine UITextView in meiner iOS-Anwendung, die eine große Menge Text anzeigt. Ich sage diesen Text dann mithilfe des Parameters für den Versatzrand der Variablen UITextView. Mein Problem ist, dass die Auffüllung der UITextView meine Berechnungen verwirrt, da sie sich abhängig von der Schriftgröße und der verwendeten Schriftart unterscheidet.

Daher stelle ich die Frage: Kann man die Auffüllung um den Inhalt der UITextView entfernen?

Freuen Sie sich auf Ihre Antworten!

425
sniurkst

Richtig aktuell für 2019

Es ist einer der dümmsten Fehler in iOS.

Die Klasse UITextViewFixed ist normalerweise eine sinnvolle Lösung.

Hier ist die Klasse:

@IBDesignable class UITextViewFixed: UITextView {
    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }
    func setup() {
        textContainerInset = UIEdgeInsets.zero
        textContainer.lineFragmentPadding = 0
    }
}

Vergessen Sie nicht, scrollEnabled im Inspector auszuschalten!

  1. Die Lösung funktioniert ordnungsgemäß im Storyboard

  2. Die Lösung funktioniert zur Laufzeit ordnungsgemäß

Das ist es, du bist fertig.

In der Regel das sollte in den meisten Fällen alles sein.

Selbst wenn Sie die Höhe der Textansicht im laufenden Betrieb ändern, genügt dies normalerweise allen Anforderungen, die Sie benötigen.

(Ein allgemeines Beispiel für das Ändern der Höhe während des Vorgangs ist das Ändern der Höhe durch den Benutzer.)

Hier ist die kaputte UITextView von Apple ...

screenshot of IB with UITextView

Hier ist UITextViewFixed:

screenshot of IB with UITextViewFixed

Beachten Sie, dass Sie natürlich müssen

deaktivieren Sie scrollEnabled im Inspector!

Vergessen Sie nicht, scrollEnabled auszuschalten! :)


Einige weitere Probleme

(1) In einigen ungewöhnlichen Fällen - zum Beispiel in einigen Fällen flexibler Zellenhöhen-Tabellensichten mit sich dynamisch ändernder Höhe - macht Apple das Ärgerlichste auf der Welt: sie fügen zusätzlichen Platz an der Unterseite hinzu .Nicht wirklich! Dies muss eines der aufregendsten Dinge in iOS sein.

Hier ist eine "schnelle Lösung" hinzuzufügen, die oft bei diesem Wahnsinn hilft.

...
        textContainerInset = UIEdgeInsets.zero
        textContainer.lineFragmentPadding = 0

        // this is not ideal, but you can sometimes use this
        // to fix the "space at bottom" insanity
        var b = bounds
        let h = sizeThatFits(CGSize(
           width: bounds.size.width,
           height: CGFloat.greatestFiniteMagnitude)
       ).height
       b.size.height = h
       bounds = b
 ...

(2) Um ein weiteres subtiles Apple-Durcheinander zu beheben, müssen Sie Folgendes hinzufügen:

override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
    super.setContentOffset(contentOffset, animated: false)
}

(3) Wir sollten hinzufügen:

contentInset = UIEdgeInsets.zero

gleich nach .lineFragmentPadding = 0 in UITextViewFixed.

Aber ... glauben oder nicht ... es funktioniert einfach nicht im aktuellen iOS! (Im Jahr 2019 eingecheckt.) Diese Zeile muss möglicherweise in der Zukunft hinzugefügt werden.

Die Tatsache, dass UITextView in iOS defekt ist, ist eines der seltsamsten Dinge in allen Bereichen des Mobile Computing. Zehn Jahre Jubiläum dieser Frage und noch immer nicht fixiert!

Zum Schluss noch ein ähnlicher Tipp für Text Field: https://stackoverflow.com/a/43099816/294884

248
Fattie

Für iOS 7.0 habe ich festgestellt, dass der contentInset-Trick nicht mehr funktioniert. Dies ist der Code, den ich verwendet habe, um die Ränder/Polsterung in iOS 7 zu beseitigen.

Dadurch wird der linke Rand des Texts am linken Rand des Containers angezeigt:

textView.textContainer.lineFragmentPadding = 0

Dadurch wird der obere Rand des Texts am oberen Rand des Containers ausgerichtet

textView.textContainerInset = .zero

Beide Linien werden benötigt, um den Rand/die Auffüllung vollständig zu entfernen.

751
user1687195

Diese Problemumgehung wurde 2009 geschrieben, als IOS 3.0 veröffentlicht wurde. Es gilt nicht mehr.

Ich stieß auf das gleiche Problem, am Ende musste ich es benutzen

nameField.contentInset = UIEdgeInsetsMake(-4,-8,0,0);

dabei ist nameField eine UITextView. Die Schriftart, die ich zufällig verwendete, war Helvetica 16 point. Es ist nur eine benutzerdefinierte Lösung für die jeweilige Feldgröße, die ich gezeichnet habe. Dadurch wird der linke Versatz bündig mit der linken Seite und der obere Versatz dort, wo ich ihn für die Box haben möchte, gezeichnet. 

Außerdem scheint dies nur für UITextViews zu gelten, wo Sie das Standard-Aligment verwenden, d.

nameField.textAlignment = NSTextAlignmentLeft;

Wenn Sie beispielsweise rechts ausrichten, scheint die Variable UIEdgeInsetsMake keinerlei Auswirkungen auf den rechten Rand zu haben.

Zumindest können Sie mit der .contentInset -Eigenschaft Ihre Felder mit den "richtigen" Positionen platzieren und die Abweichungen berücksichtigen, ohne Ihre UITextViews zu verschieben.

250
Michael

Ausgehend von den guten Antworten, die bereits gegeben wurden, handelt es sich um eine rein Interface Builder-basierte Lösung, die die benutzerdefinierten Laufzeitattribute verwendet und in iOS 7.0+ funktioniert:

enter image description here

68
azdev

Unter iOS 5 scheint UIEdgeInsetsMake(-8,-8,-8,-8); großartig zu funktionieren.

44
Engin Kurutepe

Ich würde definitiv alle Antworten mit hartcodierten Werten vermeiden, da sich die tatsächlichen Ränder mit den Einstellungen der Schriftgröße des Benutzers usw. ändern können.

Hier ist die Antwort von @ user1687195, ohne den textContainer.lineFragmentPadding zu ändern (da der docs -Zustand dies nicht der beabsichtigte Gebrauch ist).

Dies funktioniert hervorragend für iOS 7 und höher.

self.textView.textContainerInset = UIEdgeInsetsMake(
                                      0, 
                                      -self.textView.textContainer.lineFragmentPadding, 
                                      0, 
                                      -self.textView.textContainer.lineFragmentPadding);

Dies ist praktisch das gleiche Ergebnis, nur ein wenig sauberer, da die lineFragmentPadding-Eigenschaft nicht missbraucht wird.

39
ldoogy

Storyboard- oder Interface Builder-Lösung mit benutzerdefinierten Laufzeitattributen . Update. Es wurden iOS7.1- und iOS6.1-Screenshots mit contentInset = {{-10, -5}, {0, 0}} .__ hinzugefügt.enter image description hereenter image description here

18
Uladzimir

Alle diese Antworten beziehen sich auf die Titelfrage, aber ich wollte einige Lösungen für die Probleme vorschlagen, die sich in der Frage der OP ergeben.

Größe des Textinhalts

Um die Größe des Textes in UITextView schnell zu berechnen, verwenden Sie NSLayoutManager:

UITextView *textView;
CGSize textSize = [textView usedRectForTextContainer:textView.textContainer].size;

Dies ergibt den gesamten scrollbaren Inhalt, der größer sein kann als der Frame von UITextView. Ich fand das viel genauer als textView.contentSize, da es tatsächlich berechnet, wie viel Platz der Text benötigt. Geben Sie beispielsweise ein leeres UITextView an:

textView.frame.size = (width=246, height=50)
textSize = (width=10, height=16.701999999999998)
textView.contentSize = (width=246, height=33)
textView.textContainerInset = (top=8, left=0, bottom=8, right=0)

Zeilenhöhe

UIFont verfügt über eine Eigenschaft, mit der Sie schnell die Zeilenhöhe für die angegebene Schriftart ermitteln können. So können Sie die Zeilenhöhe des Texts in Ihrem UITextView schnell finden mit:

UITextView *textView;
CGFloat lineHeight = textView.font.lineHeight;

Berechnung der sichtbaren Textgröße

Das Ermitteln der tatsächlich sichtbaren Textmenge ist für die Behandlung eines "Paging" -Effekts wichtig. UITextView hat eine Eigenschaft mit dem Namen textContainerInset, die eigentlich eine Grenze zwischen dem tatsächlichen UITextView.frame und dem Text selbst ist. Um die tatsächliche Höhe des sichtbaren Rahmens zu berechnen, können Sie die folgenden Berechnungen durchführen:

UITextView *textView;
CGFloat textViewHeight = textView.frame.size.height;
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textHeight = textViewHeight - textInsets.top - textInsets.bottom;

Ermitteln der Paging-Größe

Nachdem Sie nun über die sichtbare Textgröße und den Inhalt verfügen, können Sie schnell ermitteln, wie Ihre Offsets aussehen sollen, indem Sie textHeight von textSize abziehen:

// where n is the page number you want
CGFloat pageOffsetY = textSize - textHeight * (n - 1);
textView.contentOffset = CGPointMake(textView.contentOffset.x, pageOffsetY);

// examples
CGFloat page1Offset = 0;
CGFloat page2Offset = textSize - textHeight
CGFloat page3Offset = textSize - textHeight * 2

Mit all diesen Methoden habe ich meine Insets nicht angefasst und ich konnte an die Einfügemarke oder an einen beliebigen Ort im gewünschten Text gehen.

15
mikeho

sie können die textContainerInset-Eigenschaft von UITextView verwenden:

textView.textContainerInset = UIEdgeInsetsMake (10, 10, 10, 10);

(oben links unten rechts)

11
Himanshu padia

Bei iOS 10 funktioniert die folgende Zeile für das Entfernen der oberen und unteren Auffüllung.

captionTextView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
8
Anson Yao

Hier ist eine aktualisierte Version von Fatties sehr hilfreicher Antwort ... und fügt zwei sehr wichtige Zeilen hinzu, die mir dabei geholfen haben, perfektes Layout für iOS 10 und 11 (und wahrscheinlich auch für niedrigere) zu erstellen.
d

@IBDesignable class UITextViewFixed: UITextView {
    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }
    func setup() {
        translatesAutoresizingMaskIntoConstraints = true
        textContainerInset = UIEdgeInsets.zero
        textContainer.lineFragmentPadding = 0
        translatesAutoresizingMaskIntoConstraints = false
    }
}

Die wichtigen Zeilen sind die beiden translatesAutoresizingMaskIntoConstraints = <true/false>-Anweisungen!

Dies überraschend entfernt alle Ränder in allen meinen Umständen! 

Während textView kein First-Responder ist, kann es vorkommen, dass ein seltsamer unterer Rand vorhanden ist, der mit der in der akzeptierten Antwort erwähnten sizeThatFits-Methode nicht gelöst werden konnte.
Beim Tippen auf das textView verschwand plötzlich der seltsame untere Rand und alles sah so aus, als sollte es aussehen, aber nur, wenn das textView firstResponder hat. 

Also lese ich hier auf SO , dass das Aktivieren und Deaktivieren von translatesAutoresizingMaskIntoConstraints hilfreich ist, wenn der Frame/die Grenzen manuell zwischen den Aufrufen festgelegt werden.

Glücklicherweise funktioniert dies nicht nur mit der Frame-Einstellung, sondern auch mit den 2 Zeilen von setup(), die zwischen den beiden translatesAutoresizingMaskIntoConstraints-Aufrufen eingefügt sind! 

Dies ist zum Beispiel sehr hilfreich bei der Berechnung des Frames einer Ansicht unter Verwendung von systemLayoutSizeFitting für eine UIView. Gibt die korrekte Größe zurück (was zuvor nicht der Fall war)!

Wie in der ursprünglichen Antwort erwähnt:
Vergiss nicht, scrollEnabled im Inspector auszuschalten!
Diese Lösung funktioniert sowohl im Storyboard als auch zur Laufzeit ordnungsgemäß.

Das ist es, jetzt sind Sie wirklich fertig!}

6
Fab1n

Für Swift 4, Xcode 9

Mit der folgenden Funktion können Sie den Rand/Abstand des Texts in UITextView ändern

public func UIEdgeInsetsMake (_ oben: CGFloat, _ links: CGFloat, _ unten: CGFloat, _ rechts: CGFloat) -> UIEdgeInsets

so in diesem Fall ist

 self.textView?.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
3
Shan Ye

Neueste Swift:

self.textView.textContainerInset = .init(top: -2, left: 0, bottom: 0, right: 0)
self.textView.textContainer.lineFragmentPadding = 0
3
Urvish Modi

Hier ist eine einfache Erweiterung, die den Standardrand von Apple aus jeder Textansicht in Ihrer App entfernt.

Hinweis: Der Interface Builder zeigt immer noch den alten Rand an, Ihre App funktioniert jedoch wie erwartet. 

extension UITextView {

   open override func awakeFromNib() {
      super.awakeFromNib();
      removeMargins();
   }

   /** Removes the Apple textview margins. */
   public func removeMargins() {
      self.contentInset = UIEdgeInsetsMake(
         0, -textContainer.lineFragmentPadding,
         0, -textContainer.lineFragmentPadding);
   }
}
2
Cal S

Bei der Inset-Lösung hatte ich immer noch rechts und unten eine Polsterung. Auch die Textausrichtung verursachte Probleme. Der einzige sichere Weg, den ich gefunden habe, war, die Textansicht in eine andere, an Grenzen begrenzte Ansicht zu stellen. 

2
rp90

Für mich (iOS 11 & Xcode 9.4.1) funktionierte das Zusammenstellen der Eigenschaft textView.font auf UIFont.preferred(forTextStyle:UIFontTextStyle) style und die erste Antwort, wie von @Fattie erwähnt, magisch. Die @Fattie-Antwort hat jedoch nicht funktioniert, bis ich die Eigenschaft textView.font gesetzt habe. Andernfalls verhält sich UITextView unberechenbar.

0
Nikhil Pandey

Falls jemand nach der neuesten Swift-Version sucht, funktioniert der folgende Code einwandfrei mit Xcode 10.2 und Swift 4.2

yourTextView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
0
Bhavin_m