Dynamisches Höhenproblem für UITableView-Zellen (Swift)


79

Dynamischer Text mit variabler Länge wird in Tabellenbeschriftungszellenbeschriftungen eingefügt. Damit die Höhen der Tabellenansichtszellen dynamisch dimensioniert werden können, habe ich Folgendes implementiert viewDidLoad():

self.tableView.estimatedRowHeight = 88.0
self.tableView.rowHeight = UITableViewAutomaticDimension

Dies funktioniert gut für die Zellen, zu denen noch UITableViewAutomaticDimentionkein Bildlauf durchgeführt werden muss (wie beim Bildlauf zur Zelle aufgerufen wird), jedoch nicht für die Zellen, die beim Laden der Tabelle mit Daten zunächst auf dem Bildschirm gerendert werden.

Ich habe versucht, die Daten einfach neu zu laden (wie in vielen anderen Ressourcen vorgeschlagen):

self.tableView.reloadData()

in beiden viewDidAppear()und viewWillAppear()und es war ohne Erfolg. Ich bin verloren. Weiß jemand, wie xcode die dynamische Höhe für die Zellen rendern kann, die ursprünglich auf dem Bildschirm geladen wurden?

Bitte lassen Sie mich wissen, ob es eine bessere alternative Methode gibt.


Sind Ihre Höhenbeschränkungen für die Einrichtung (en) der Zelle (n) korrekt, habe ich mit der Xcode 6.3-Version keine Probleme damit in freier Wildbahn gesehen. Habe sogar ein Beispielprojekt auf Github mit dieser Arbeit. github.com/darren102/DTFAutomaticCellHeight
darren102

1
Ich habe dieses Problem gelöst, indem ich die potenzielle Höhe des Etiketts überkompensiert habe. Bitte sehen Sie meine Antwort unten. Egal, wenn Sie eine bessere Lösung haben, lassen Sie es mich bitte wissen!
Simplexität

Antworten:


114

Versuche dies:

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

BEARBEITEN

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Swift 4

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Swift 4.2

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}

Definieren Sie oben beide Methoden.
Es löst das Problem.

PS: Damit dies funktioniert, sind obere und untere Einschränkungen erforderlich.

Hier ist ein Beispiel


3
@ Bashan Es funktioniert perfekt. Stellen Sie sicher, dass Sie die richtigen Einschränkungen angegeben haben.
iDhaval

2
Funktioniert nicht Es scheint einen Fehler zu geben, wenn ein Wort einfach zu lang, aber nicht lang genug ist, wird es nicht richtig gerendert. Wenn es ein paar Worte sind, scheint es richtig zu funktionieren.
Jeeves

6
Dies hat bei mir nicht funktioniert, bis ich eine untere Einschränkung hinzugefügt habe. Ich denke, es ist erwähnenswert in Ihrer Antwort, dass obere und untere Einschränkungen festgelegt werden müssen, damit dies funktioniert.
Mitch Downey

2
Damit dies funktioniert, sind untere und obere Einschränkungen erforderlich.
Antony Ouseph

2
Damit dies funktioniert, sind untere und obere Einschränkungen für die "
Zellenelemente

37

Benutze das:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300

und nicht verwenden: heightForRowAtIndexPathFunktion delegieren

Stellen Sie im Storyboard auch nicht die Höhe des Etiketts ein, das eine große Datenmenge enthält. Gib ihm top, bottom, leading, trailingEinschränkungen.


4
Bottom-Constraint ist wichtig! Ich habe das verpasst und mich gefragt, warum die Höhe nicht berechnet werden konnte.
Cyer

Ich ließ diesenheightForRowAtIndexPath
500 Server Fehler

@Javeed Ich denke, Sie können es überall wie statische Zelle oder dynamische Zelle verwenden ..
ami

16

SWIFT 3

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160

UND!!! In storyBoard: Sie MÜSSEN TOP & BOTTOM-Einschränkungen für Ihr Label festlegen. Nichts anderes.


11

Dieser seltsame Fehler wurde durch Interface Builder-Parameter behoben, da die anderen Antworten das Problem nicht lösten.

Ich habe lediglich die Standardetikettengröße größer gemacht, als der Inhalt möglicherweise sein könnte, und sie auch in der estimatedRowHeightHöhe wiedergegeben. Zuvor habe ich die Standardzeilenhöhe in Interface Builder auf festgelegt 88pxund in meinem Controller wie folgt wiedergegeben viewDidLoad():

self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0

Aber das hat nicht funktioniert. Also wurde mir klar, dass der Inhalt niemals größer werden würde als vielleicht 100px, also setzte ich die Standardzellenhöhe auf 108px(größer als der potenzielle Inhalt) und spiegelte sie wie folgt im Controller wider viewDidLoad():

self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 108.0

Dies tatsächlich den Code darf schrumpfen die ersten Etiketten auf die richtige Größe. Mit anderen Worten, es wurde nie größer, konnte aber immer kleiner werden ... Außerdem wurde kein zusätzliches self.tableView.reloadData()benötigt viewWillAppear().

Ich weiß, dass dies keine stark variablen Inhaltsgrößen abdeckt, aber dies funktionierte in meiner Situation, in der der Inhalt eine maximal mögliche Zeichenanzahl hatte.

Ich bin mir nicht sicher, ob dies ein Fehler in Swift oder Interface Builder ist, aber es funktioniert wie ein Zauber. Versuche es!


Ich habe auch das gleiche Problem. Ich habe meine Antwort aktualisiert. es hat mein Problem gelöst. Definieren Sie einfach nur diese Methode und entfernen Sie alle mit der Höhe verbundenen Elemente.
iDhaval

8

Stellen Sie die automatische Abmessung für die Zeilenhöhe und die geschätzte Zeilenhöhe ein und stellen Sie die folgenden Schritte sicher:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Set automatic dimensions for row height
    // Swift 4.2 onwards
    table.rowHeight = UITableView.automaticDimension
    table.estimatedRowHeight = UITableView.automaticDimension


    // Swift 4.1 and below
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension

}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // Swift 4.2 onwards
    return UITableView.automaticDimension

    // Swift 4.1 and below
    return UITableViewAutomaticDimension
}

Zum Beispiel: Wenn Sie eine Beschriftung in Ihrer UITableviewCell haben, dann

  • Stellen Sie die Anzahl der Zeilen auf 0 ein (& Zeilenumbruchmodus = Schwanz abschneiden)
  • Legen Sie alle Einschränkungen (oben, unten, rechts links) in Bezug auf die Übersicht / den Zellencontainer fest.
  • Optional : Legen Sie die Mindesthöhe für das Etikett fest, wenn der vertikale Mindestbereich durch das Etikett abgedeckt werden soll, auch wenn keine Daten vorhanden sind.

Hier ist ein Beispieletikett mit dynamischen Höhenbeschränkungen.

Geben Sie hier die Bildbeschreibung ein


1
Der von Krunal erwähnte Eintrag in ViewDidLoad () war die Lösung für mich.
SHS

7

Die dynamische Größenzelle von UITableView erforderte zwei Dinge

  1. Festlegen der richtigen Einschränkung Ihrer Ansicht in der Zelle der Tabellenansicht (meistens umfasst dies das Festlegen der richtigen Einschränkungen für die Ansicht von oben, unten und Traling für Ihre Ansicht).
  2. Aufrufen dieser Eigenschaften von TableView in viewDidLoad ()

     tableView.rowHeight = UITableViewAutomaticDimension
    
     tableView.estimatedRowHeight = 140
    

Dies ist ein wunderbares Tutorial zur Selbstgröße (dynamische Tabellenansichtszellen), das in Swift 3 geschrieben wurde.


6

Für Swift 3 können Sie Folgendes verwenden:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

3

Für Swift 4.2

@IBOutlet weak var tableVw: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Set self as tableView delegate
    tableVw.delegate = self

    tableVw.rowHeight = UITableView.automaticDimension
    tableVw.estimatedRowHeight = UITableView.automaticDimension
}

// UITableViewDelegate Method 
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return UITableView.automaticDimension
}

Viel Spaß beim Codieren :)


2

Versuchen

override func viewWillAppear(animated: Bool) {
    self.tableView.layoutSubviews()
}

Ich hatte das gleiche Problem und es funktioniert bei mir.


Ich werde es versuchen und Sie wissen lassen, was passiert. Danke für den Vorschlag! Fast ein Jahr nach meiner Frage habe ich außer meiner eigenen keine andere Antwort gefunden! Hoffe, deine Werke!
Simplexität

Stellen Sie sicher, dass Sie super.viewWillAppear (animiert) aufrufen, bevor Sie Layoutsubviews
Alan Scarpa

2

Stellen Sie sicher, dass Sie die folgenden Änderungen vornehmen, damit die automatische Größenänderung von UITableViewCell funktioniert:

  • In Storyboard sollte Ihre UITableView nur dynamische Prototypzellen enthalten (es sollten keine statischen Zellen verwendet werden), da sonst die automatische Größenänderung nicht funktioniert.
  • Im Storyboard hat das UILabel Ihres UITableViewCell für alle 4 Einschränkungen konfiguriert, nämlich die oberen, unteren, führenden und nachfolgenden Einschränkungen.
  • Im Storyboard sollte die Anzahl der Zeilen Ihres UITableViewCell-UILabels 0 sein
  • In der viewDidLoad-Funktion Ihres UIViewControllers, die unter den UITableView-Eigenschaften festgelegt ist:

    self.tableView.estimatedRowHeight = <minimum cell height> 
    self.tableView.rowHeight = UITableViewAutomaticDimension
    

Wie implementiere ich dasselbe mit statischen Zellen?
Javeed

Nach dem Versuch , alle hier angebotenen Lösungen, nur diese ein (Einstellung des <minimum cell height>für estimatedRowHeight) mein Problem wirklich behoben. Zuvor hatte die Zelle eine automatische Größenänderung, aber ich erhielt auch verschiedene Warnungen zu Einschränkungen. Jetzt tue ich nicht! Also, vielen Dank, Anshul !!
RoberRM

2

Für Swift habe ich diese Antwort auch in iOS 9.0 und iOS 11 überprüft (Xcode 9.3).

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Hier müssen Sie obere, untere, rechte und linke Einschränkungen hinzufügen


2

In meinem Fall - Im Storyboard hatte ich zwei Beschriftungen wie im Bild unten. Bei beiden Beschriftungen wurden die gewünschten Breitenwerte festgelegt, bevor ich sie gleich machte. Sobald Sie die Auswahl aufheben, wechselt sie zu automatisch, und wie üblich sollte es wie Charme funktionieren, wenn Sie unten stehen.

1.rowHeight = UITableView.automaticDimension, and
2.estimatedRowHeight = 100(In my case).
3.make sure label number of lines is zero.

Geben Sie hier die Bildbeschreibung ein


2

Dies ist einfach, wenn Sie zwei Dinge tun:

  1. Einstellen der automatischen Höhe
tableView.rowHeight = UITableView.automaticDimension
  1. Erstellen aller TableViewCells mit FULL- Einschränkungen von oben nach unten. Das letzte Element MUSS einen unteren Abstand definieren, um die Zelle zu beenden.

So kann die Layout-Engine die Zellenhöhe berechnen und den Wert korrekt anwenden.


1

Ich war nur von Ihrer Lösung inspiriert und habe einen anderen Weg versucht.

Bitte versuchen Sie es hinzufügen tableView.reloadData()zu viewDidAppear().

Das funktioniert bei mir.

Ich denke, die Dinge hinter dem Scrollen sind "die gleichen" wie reloadData. Wenn Sie durch den Bildschirm scrollen, ist es, reloadData()als würden Sie anrufen, wann viewDidAppear.

Wenn dies funktioniert, antworten Sie bitte auf diese Antwort, damit ich mir dieser Lösung sicher sein kann.


Ich werde es versuchen und aktualisieren, um zu sehen, ob es die gleiche Lösung erstellt. Vielen Dank!
Simplexität

Sorry Kang, seltsamerweise hatte es keinen Einfluss auf das Layout. Sie wurden als statischer Wert beibehalten, der wie im Interface Builder festgelegt wurde, anstatt sie auf die richtige Größe zu verkleinern.
Simplexität

1

Leider bin ich mir nicht sicher, was mir gefehlt hat. Die oben genannten Methoden funktionieren bei mir nicht, um die Höhe der xib-Zelle zu ermitteln, oder lassen Sie layoutifneeded () oder UITableView.automaticDimension die Höhenberechnung durchführen. Ich habe 3 bis 4 Nächte gesucht und versucht, konnte aber keine Antwort finden. Einige Antworten hier oder in einem anderen Beitrag gaben mir jedoch Hinweise für die Problemumgehung. Es ist eine dumme Methode, aber es funktioniert. Fügen Sie einfach alle Ihre Zellen zu einem Array hinzu. Stellen Sie dann den Ausgang jeder Ihrer Höhenbeschränkungen im xib-Storyboard ein. Addieren Sie sie schließlich in der heightForRowAt-Methode. Es ist einfach, wenn Sie mit diesen APIs nicht vertraut sind.

Swift 4.2

CustomCell.Swift

@IBOutlet weak var textViewOneHeight: NSLayoutConstraint!
@IBOutlet weak var textViewTwoHeight: NSLayoutConstraint!
@IBOutlet weak var textViewThreeHeight: NSLayoutConstraint!

@IBOutlet weak var textViewFourHeight: NSLayoutConstraint!
@IBOutlet weak var textViewFiveHeight: NSLayoutConstraint!

MyTableViewVC.Swift

.
.
var myCustomCells:[CustomCell] = []
.
.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = Bundle.main.loadNibNamed("CustomCell", owner: self, options: nil)?.first as! CustomCell

.
.
myCustomCells.append(cell)
return cell

}


override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

   let totalHeight = myCustomCells[indexPath.row].textViewOneHeight.constant + myCustomCells[indexPath.row].textViewTwoHeight.constant +  myCustomCells[indexPath.row].textViewThreeHeight.constant + myCustomCells[indexPath.row].textViewFourHeight.constant + myCustomCells[indexPath.row].textViewFiveHeight.constant

  return totalHeight + 40 //some magic number


}

1

Ich benutze diese

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return 100
}

1

Zusätzlich zu dem, was andere gesagt haben,

Stellen Sie die Einschränkungen Ihres Etiketts in Bezug auf die Übersicht ein!

Anstatt die Einschränkungen Ihres Etiketts relativ zu anderen Elementen zu platzieren, beschränken Sie es auf die Inhaltsansicht der Zellen der Tabellenansicht.

Stellen Sie dann sicher, dass die Höhe Ihres Etiketts auf mehr als oder gleich 0 und die Anzahl der Zeilen auf 0 eingestellt ist.

Dann ViewDidLoadfügen Sie hinzu:

tableView.estimatedRowHeight = 695

tableView.rowHeight = UITableViewAutomaticDimension

0

Sie sollten einfach alle Einschränkungen für TOP , BOTTOM und HEIGHT für jedes Objekt in der Zellenansicht / den Zellenansichten festlegen und die vorhandene mittlere Y- Position entfernen, falls vorhanden. Denn wo Sie dies nicht getan haben, werden Artefakte in andere Ansichten eingefügt.


3
Hallo! Diese Antwort mag gut sein, aber es ist besser, ein funktionierendes Beispiel zu liefern, das Ihre Antwort erklärt und demonstriert.
ItamarG3

0

Für Ziel c ist dies eine meiner schönen Lösungen. es hat bei mir funktioniert.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    cell.textLabel.text = [_nameArray objectAtIndex:indexPath.row];
    cell.textLabel.numberOfLines = 0;
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

Wir müssen diese 2 Änderungen anwenden.

1)cell.textLabel.numberOfLines = 0;
  cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;

2)return UITableViewAutomaticDimension;

0

Ich hatte dieses Problem anfangs auch, ich hatte mein Problem durch diesen Code behoben und versucht, die Verwendung von self.tableView.reloadData()anstelle dieses Codes für die dynamische Höhe zu vermeiden

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

0

Bei Verwendung einer Statik UITableViewsetze ich alle Werte im UILabels und rufe dann auf tableView.reloadData().


0
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0

Und vergessen Sie nicht, Botton-Einschränkungen für das Etikett hinzuzufügen


0

Swift 5 Viel Spaß

tablev.rowHeight = 100
tablev.estimatedRowHeight = UITableView.automaticDimension


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tablev.dequeueReusableCell(withIdentifier: "ConferenceRoomsCell") as! ConferenceRoomsCell
    cell.lblRoomName.numberOfLines = 0
    cell.lblRoomName.lineBreakMode = .byWordWrapping
    cell.lblRoomName.text = arrNameOfRooms[indexPath.row]
    cell.lblRoomName.sizeToFit()
    return cell
}

-1
self.Itemtableview.estimatedRowHeight = 0;
self.Itemtableview.estimatedSectionHeaderHeight = 0;
self.Itemtableview.estimatedSectionFooterHeight = 0;


[ self.Itemtableview reloadData];
self.Itemtableview.frame = CGRectMake( self.Itemtableview.frame.origin.x,  self.Itemtableview.frame.origin.y,  self.Itemtableview.frame.size.width,self.Itemtableview.contentSize.height + self.Itemtableview.contentInset.bottom + self.Itemtableview.contentInset.top);

Während dieser Code die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und anzugeben, welche Einschränkungen und Annahmen gelten.
Suraj Rao

-3

Legen Sie die richtige Einschränkung fest und aktualisieren Sie die Delegatenmethoden wie folgt:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Dadurch wird das Problem der dynamischen Zellenhöhe behoben. WENN nicht, müssen Sie die Einschränkungen überprüfen.


1
Gleicher Code wie Ahmed Lotfys Antwort auf derselben Seite ...
Eric Aya

Hmmm, ich habe nach schnellen 3 gesucht. *, Ich habe Ahmed ans
Kanjariya-IOS

1
Sie müssen auch die geschätzte
Zeilenhöhe angeben, damit
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.