Problem z dynamiczną wysokością dla komórek UITableView (Swift)


79

Dynamiczny tekst o zmiennej długości jest wstawiany do etykiet komórek widoku tabeli. Aby wysokości komórek widoku tabeli były dynamicznie zmieniane, zaimplementowałem w viewDidLoad():

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

Działa to dobrze w przypadku komórek, które nie zostały jeszcze przewinięte (jak UITableViewAutomaticDimentionjest wywoływane podczas przewijania do komórki), ale nie w przypadku komórek, które są początkowo renderowane na ekranie po załadowaniu tabeli z danymi.

Próbowałem po prostu przeładować dane (jak sugerowano w wielu innych zasobach):

self.tableView.reloadData()

w obu viewDidAppear()i viewWillAppear()i bezskutecznie. Zgubiłem się ... czy ktoś wie, jak sprawić, by xcode renderował dynamiczną wysokość komórek ładowanych początkowo na ekranie?

Daj mi znać, jeśli istnieje lepsza metoda alternatywna.


Czy ograniczenia wysokości dla komórki (komórek) są prawidłowo skonfigurowane, nie widziałem żadnych problemów z tym na wolności przy użyciu wersji Xcode 6.3. Masz nawet przykładowy projekt na githubie z tym działaniem. github.com/darren102/DTFAutomaticCellHeight
darren102

1
Rozwiązałem ten problem, nadmiernie kompensując potencjalną wysokość etykiety. Zobacz moją odpowiedź poniżej. Niezależnie od tego, jeśli masz lepsze rozwiązanie, daj mi znać!
prostota

Odpowiedzi:


115

Spróbuj tego:

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

EDYTOWAĆ

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

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

Zdefiniuj powyżej Obie metody.
Rozwiązuje problem.

PS: Aby to zadziałało, wymagane są ograniczenia na górze i na dole.

Oto przykład


3
@bashan Działa idealnie. Upewnij się, że podałeś odpowiednie ograniczenia.
iDhaval

2
Nie działa. Wydaje się, że wystąpił błąd, jeśli słowo jest po prostu zbyt długie, ale nie wystarczająco długie, nie jest poprawnie renderowane. Jeśli jest to kilka słów, wydaje się, że działa poprawnie.
Jeeves,

6
To nie zadziałało, dopóki nie dodałem dolnego ograniczenia. Myślę, że warto zauważyć w swojej odpowiedzi, że górne i dolne ograniczenia muszą być ustawione, aby to zadziałało.
Mitch Downey

2
Aby to zadziałało, wymagane są ograniczenia dolne i górne.
Antony Ouseph

2
Aby to zadziałało, wymagane są dolne i górne ograniczenia dla „elementów komórki”
EnasAZ,

37

Użyj tego:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300

i nie używaj: heightForRowAtIndexPathfunkcji delegowania

Ponadto w scenorysie nie ustawiaj wysokości etykiety, która zawiera dużą ilość danych. Daj mu top, bottom, leading, trailingograniczenia.


4
Ograniczenie dna jest ważne! Brakowało mi tego i zastanawiałem się, dlaczego nie można obliczyć wysokości.
coyer

Zostawiłem toheightForRowAtIndexPath
błąd serwera 500

@Javeed Myślę, że możesz go używać wszędzie, np. Komórka statyczna lub komórka dynamiczna ..
ami rt

16

SWIFT 3

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160

I!!! W storyBoard: MUSISZ ustawić górne i dolne ograniczenia dla swojej etykiety. Nic więcej.


11

Ten dziwny błąd został rozwiązany za pomocą parametrów Interface Builder, ponieważ inne odpowiedzi nie rozwiązały problemu.

Jedyne, co zrobiłem, to zwiększyć domyślny rozmiar etykiety, niż potencjalnie mogłaby być treść, i odzwierciedlić to również w estimatedRowHeightwysokości. Wcześniej ustawiałem domyślną wysokość wiersza w Interface Builder na 88pxi odzwierciedlałem to w ten sposób w moim kontrolerze viewDidLoad():

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

Ale to nie zadziałało. Więc zdałem sobie sprawę, że zawartość nigdy nie stanie się większa niż być może 100px, więc ustawiłem domyślną wysokość komórki na 108px(większą niż potencjalna zawartość) i odzwierciedlam to w kontrolerze viewDidLoad():

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

To faktycznie pozwoliło kodowi zmniejszyć początkowe etykiety do odpowiedniego rozmiaru. Innymi słowy, nigdy nie rozszerzył się do większego rozmiaru, ale zawsze mógł się skurczyć ... Poza tym nie self.tableView.reloadData()było potrzeby dodatkowego viewWillAppear().

Wiem, że nie obejmuje to bardzo zmiennych rozmiarów treści, ale zadziałało to w mojej sytuacji, w której treść miała maksymalną możliwą liczbę znaków.

Nie jestem pewien, czy jest to błąd w Swift lub Interface Builder, ale działa jak urok. Spróbuj!


Mam też ten sam problem. Zaktualizowałem odpowiedź. rozwiązało mój problem. po prostu zdefiniuj tylko tę metodę i usuń wszystkie rzeczy związane z wysokością.
iDhaval

8

Ustaw automatyczny wymiar wysokości i szacowanej wysokości wiersza i wykonaj następujące czynności:

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

Na przykład: jeśli masz etykietę w swoim UITableviewCell,

  • Ustaw liczbę linii = 0 (& tryb łamania linii = obetnij koniec)
  • Ustaw wszystkie ograniczenia (góra, dół, prawy lewy) w odniesieniu do jego kontenera nadzoru / komórki.
  • Opcjonalnie : ustaw minimalną wysokość etykiety, jeśli chcesz, aby minimalny obszar w pionie był pokryty etykietą, nawet jeśli nie ma danych.

Oto przykładowa etykieta z dynamicznymi ograniczeniami wysokości.

wprowadź opis obrazu tutaj


1
Wpis w ViewDidLoad (), o którym wspomniał Krunal, był dla mnie rozwiązaniem.
SHS

7

Dynamiczna komórka rozmiaru UITableView wymagała 2 rzeczy

  1. Ustawienie odpowiedniego ograniczenia widoku w komórce widoku tabeli (głównie obejmuje to zapewnienie odpowiedniego widoku górnego, dolnego i górnego)
  2. Wywołanie tych właściwości TableView w viewDidLoad ()

     tableView.rowHeight = UITableViewAutomaticDimension
    
     tableView.estimatedRowHeight = 140
    

To jest cudowny samouczek dotyczący samorozmiaru (komórki dynamicznego widoku tabeli) napisany w języku Swift 3.


6

W przypadku Swift 3 możesz użyć:

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

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

3

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

Miłego kodowania :)


2

Próbować

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

Miałem ten sam problem i u mnie to działa.


Spróbuję i dam ci znać, co się stanie. Dzieki za sugestie! Prawie rok po zapytaniu nie znalazłem innej odpowiedzi poza własną! Mam nadzieję, że Twoje dzieło!
prostota

Upewnij się, aby zadzwonić super.viewWillAppear (animowane) przed wywołaniem layoutsubviews
Alan Scarpa

2

Aby autoregulacja UITableViewCell działała, upewnij się, że wprowadzasz te zmiany:

  • W Storyboard twój UITableView powinien zawierać tylko komórki dynamicznego prototypu (nie powinien używać statycznych komórek), w przeciwnym razie autorezacja nie zadziała.
  • W Storyboard twój UITableViewCell's UILabel został skonfigurowany dla wszystkich 4 ograniczeń, czyli ograniczeń górnego, dolnego, wiodącego i końcowego.
  • W Storyboard liczba wierszy UITableViewCell w UILabel powinna wynosić 0
  • W funkcji viewDidLoad Twojego UIViewControllera ustawionej poniżej właściwości UITableView:

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

Jak zaimplementować to samo za pomocą komórek statycznych?
Javeed

Po wypróbowaniu wszystkich oferowanych tutaj rozwiązań, tylko to (ustawienie <minimum cell height>for estimatedRowHeight) naprawdę rozwiązało mój problem. Wcześniej komórka dokonywała autorezyzacji, ale otrzymywałem też różne ostrzeżenia o ograniczeniach. Teraz nie! Więc bardzo dziękuję, Anshul !!
RoberRM

2

Dla Swift sprawdziłem tę odpowiedź również w iOS 9.0 i iOS 11 (Xcode 9.3)

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

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

Tutaj musisz dodać górne, dolne, prawe i lewe ograniczenia


2

W moim przypadku - w scenorysie miałem dwie etykiety, jak na poniższym obrazku, obie etykiety miały ustawione pożądane wartości szerokości, zanim je wyrównałem. po odznaczeniu zmieni się na automatyczny i jak zwykle posiadanie poniższych rzeczy powinno działać jak urok.

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

wprowadź opis obrazu tutaj


2

Oprócz tego, co powiedzieli inni,

USTAW OGRANICZENIA DOTYCZĄCE ETYKIETY W ODNIESIENIU DO WERYFIKACJI!

Dlatego zamiast umieszczać ograniczenia etykiety względem innych elementów wokół niej, ogranicz ją do widoku zawartości komórki widoku tabeli.

Następnie upewnij się, że wysokość etykiety jest większa lub równa 0, a liczba wierszy jest ustawiona na 0.

Następnie ViewDidLoaddodaj:

tableView.estimatedRowHeight = 695

tableView.rowHeight = UITableViewAutomaticDimension

USTAW OGRANICZENIA ETYKIETY W ODNIESIENIU DO WERYFIKACJI!: ZAOSZCZĘDZIŁEM MOJE GODZINY !! Dziękuję Ci.
ACAkgul

2

Jest to proste, gdy robisz 2 rzeczy:

  1. ustawienie automatycznej wysokości
tableView.rowHeight = UITableView.automaticDimension
  1. tworzenie wszystkich TableViewCells z FULL ograniczeniami od góry do dołu. Ostatni element MUSI zdefiniować jakiś dolny odstęp, aby zakończyć komórkę.

Dzięki temu silnik układu może obliczyć wysokość komórki i poprawnie zastosować wartość.


1

Zainspirowało mnie Twoje rozwiązanie i spróbowałem innego sposobu.

Spróbuj dodać tableView.reloadData()do viewDidAppear().

To działa dla mnie.

Myślę, że przewijanie to „to samo”, co reloadData. Kiedy przewijasz ekran, to tak, jakbyś dzwonił, reloadData()kiedy viewDidAppear.

Jeśli to zadziała, proszę odpowiedzieć na tę odpowiedź, abym mógł być pewien tego rozwiązania.


Spróbuję i zaktualizuję, aby sprawdzić, czy tworzy to samo rozwiązanie. Dzięki!
prostota

Przepraszam Kang, o dziwo nie miało to wpływu na układ. Zostawił je jako wartość statyczną, którą ustawiono tak, jak w Interface Builder, zamiast zmniejszać zawijanie ich do odpowiedniego rozmiaru.
prostota

1

Niestety nie jestem pewien, czego mi brakowało. Powyższe metody nie działają dla mnie, aby uzyskać wysokość komórki xib lub pozwolić layoutifneeded () lub UITableView.automaticDimension na wykonanie obliczenia wysokości. Szukałem i próbowałem przez 3 do 4 nocy, ale nie mogłem znaleźć odpowiedzi. Niektóre odpowiedzi tutaj lub w innym poście dały mi jednak wskazówki dotyczące obejścia tego problemu. To głupia metoda, ale działa. Po prostu dodaj wszystkie swoje komórki do tablicy. A następnie ustaw wylot każdego ograniczenia wysokości w scenorysie xib. Na koniec dodaj je w metodzie heightForRowAt. Jeśli nie znasz tych interfejsów API, jest to proste.

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

Używam tych

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

    return 100
}

0

Powinieneś po prostu ustawić wszystkie ograniczenia GÓRA , DÓŁ i WYSOKOŚĆ dla każdego obiektu w widoku / widokach komórek i usunąć istniejącą środkową pozycję Y, jeśli tak. Ponieważ tam, gdzie tego nie zrobiłeś, umieszcza artefakty na innych widokach.


3
Cześć! Ta odpowiedź może być dobra, ale lepiej podać działający przykład, który wyjaśnia i demonstruje twoją odpowiedź.
ItamarG3

0

Dla celu c jest to jedno z moich fajnych rozwiązań. to działa dla mnie.

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

Musimy zastosować te 2 zmiany.

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

2)return UITableViewAutomaticDimension;

0

Miałem również ten problem na początku, rozwiązałem swój problem z tego kodu, spróbuj uniknąć użycia self.tableView.reloadData()zamiast tego kodu dla dynamicznej wysokości

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

0

Używając statycznego UITableView, ustawiam wszystkie wartości w UILabels, a następnie wywołuję tableView.reloadData().


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

I nie zapomnij dodać dolnych ograniczeń dla etykiety


0

Swift 5 Ciesz się

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

Chociaż ten kod może rozwiązać problem, w tym wyjaśnienie, jak i dlaczego to rozwiązuje problem, naprawdę pomogłoby poprawić jakość twojego posta i prawdopodobnie zaowocowałoby większą liczbą pozytywnych głosów. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a nie tylko osoba, która zapyta teraz. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia.
Suraj Rao

-3

Ustaw odpowiednie ograniczenie i zaktualizuj metody delegata jako:

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

To rozwiąże problem z dynamiczną wysokością komórki. JEŚLI nie, musisz sprawdzić ograniczenia.


1
Ten sam kod, co odpowiedź Ahmeda Lotfy na tej samej stronie ...
Eric Aya,

Hmmm, sprawdziłem na swift 3. *, brakowało mi Ahmeda
Kanjariya-IOS

1
aby kod działał, musisz podać szacunkową wysokość wiersza
Mohsen Shakiba,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.