Mam UITableView
niestandardowy UITableViewCell
zdefiniowany w scenorysie przy użyciu układu automatycznego. Komórka ma kilka multilinii UILabels
.
Że UITableView
wydaje się właściwie oblicz wysokościach komórkowych, ale dla kilku pierwszych komórek wysokość nie jest właściwie podzielone pomiędzy etykietami. Po pewnym przewinięciu wszystko działa zgodnie z oczekiwaniami (nawet komórki, które początkowo były niepoprawne).
- (void)viewDidLoad {
[super viewDidLoad]
// ...
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"];
// ...
// Set label.text for variable length string.
return cell;
}
Czy jest coś, czego może mi brakować, co powoduje, że auto layout nie jest w stanie wykonać swojej pracy kilka pierwszych razy?
Stworzyłem przykładowy projekt, który demonstruje takie zachowanie.
ios
uitableview
ios8
autolayout
ios-autolayout
blackp
źródło
źródło
Odpowiedzi:
Nie wiem, czy jest to wyraźnie udokumentowane, czy nie, ale dodanie
[cell layoutIfNeeded]
przed zwróceniem komórki rozwiązuje problem.źródło
-layoutIfNeeded
w komórce-awakeFromNib
. Wolę dzwonić tylkolayoutIfNeeded
tam, gdzie wiem, dlaczego jest to konieczne.U mnie to działało, gdy inne podobne rozwiązania nie:
Wydaje się, że jest to rzeczywisty błąd, ponieważ znam bardzo dobrze układ AutoLayout i sposób korzystania z UITableViewAutomaticDimension, jednak nadal czasami napotykam ten problem. Cieszę się, że w końcu znalazłem coś, co działa jako obejście.
źródło
super.didMoveToSuperview()
didMoveToSuperview
: „Domyślna implementacja tej metody nic nie robi”.Dodanie
[cell layoutIfNeeded]
wcellForRowAtIndexPath
nie działa dla komórek, które są początkowo przewinęły out-of-view.Ani też poprzedzanie go
[cell setNeedsLayout]
.Nadal musisz przewinąć niektóre komórki i wrócić do widoku, aby poprawnie zmienić rozmiar.
Jest to dość frustrujące, ponieważ większość programistów ma poprawnie działające dynamiczne typy, układy AutoLayout i Self-Sizing Cells - z wyjątkiem tego irytującego przypadku. Ten błąd dotyczy wszystkich moich „wyższych” kontrolerów widoku tabeli.
źródło
[cell layoutSubviews]
zamiast layoutIfNeeded może być możliwe do naprawienia. Skorzystaj ze strony stackoverflow.com/a/33515872/1474113Miałem takie samo doświadczenie w jednym z moich projektów.
Dlaczego tak się dzieje?
Komórka zaprojektowana w Storyboard z pewną szerokością dla niektórych urządzeń. Na przykład 400px. Na przykład Twoja etykieta ma taką samą szerokość. Kiedy ładuje się z storyboardu, ma szerokość 400px.
Oto problem:
tableView:heightForRowAtIndexPath:
wywołane przed układem komórki to podwidoki.Więc obliczył wysokość etykiety i komórki o szerokości 400 pikseli. Ale uruchamiasz na urządzeniu z ekranem, na przykład 320px. Ta automatycznie obliczona wysokość jest nieprawidłowa. Tylko dlatego, że komórka
layoutSubviews
dzieje się dopiero potableView:heightForRowAtIndexPath:
Nawet jeślipreferredMaxLayoutWidth
ręcznie ustawisz etykietę,layoutSubviews
to nie pomaga.Moje rozwiązanie:
1) Podklasa
UITableView
i nadpisaniedequeueReusableCellWithIdentifier:forIndexPath:
. Ustaw szerokość komórki równą szerokości tabeli i wymuś układ komórki.2) Podklasa
UITableViewCell
. UstawpreferredMaxLayoutWidth
ręcznie dla swoich etykiet w formacielayoutSubviews
. Potrzebujesz również układu ręcznegocontentView
, ponieważ nie układa się automatycznie po zmianie ramki komórki (nie wiem dlaczego, ale tak jest)źródło
cell.frame.size.width = tableview.frame.width
Następniecell.layoutIfNeeded()
wcellForRowAt
funkcji wystarczyły dla mnieMam podobny problem, przy pierwszym ładowaniu wysokość wiersza nie została obliczona ale po jakimś przewinięciu lub przejściu do innego ekranu i wracam do tego ekranu są obliczane wiersze. Przy pierwszym ładowaniu moje elementy są ładowane z Internetu, a przy drugim ładowaniu moje elementy są najpierw ładowane z danych podstawowych i ponownie ładowane z Internetu. Zauważyłem, że wysokość wierszy jest obliczana przy przeładowaniu z Internetu. Zauważyłem więc, że gdy tableView.reloadData () jest wywoływana podczas animacji płynnej (ten sam problem z wypychaniem i obecnym płynem), wysokość wiersza nie została obliczona. Więc ukryłem widok tabeli podczas inicjalizacji widoku i umieściłem program ładujący aktywność, aby zapobiec brzydkiemu efektowi dla użytkownika, i wywołuję tableView.reloadData po 300 ms, a teraz problem został rozwiązany. Myślę, że to błąd UIKit, ale to obejście załatwia sprawę.
Umieściłem te wiersze (Swift 3.0) w moim module obsługi zakończenia ładowania przedmiotu
To wyjaśnia, dlaczego dla niektórych osób umieszczenie reloadData w layoutSubviews rozwiązuje problem
źródło
żadne z powyższych rozwiązań u mnie nie zadziałało, zadziałał ten przepis na magię: zadzwoń do nich w tej kolejności:
tableView.reloadData()
tableView.layoutIfNeeded() tableView.beginUpdates() tableView.endUpdates()
moje dane tableView są wypełniane z usługi internetowej, w wywołaniu zwrotnym połączenia piszę powyższe wiersze.
źródło
W moim przypadku ostatnia linia UILabel została obcięta, gdy komórka była wyświetlana po raz pierwszy. Zdarzyło się to dość przypadkowo i jedynym sposobem na poprawne określenie rozmiaru było przewinięcie komórki z widoku i przywrócenie jej. Wypróbowałem wszystkie możliwe rozwiązania wyświetlane do tej pory (layoutIfNeeded..reloadData), ale nic nie działało. Sztuczka polegała na ustawieniu „Autoshrink” na Minimuum Font Scale (dla mnie 0.5). Spróbuj
źródło
Dodaj ograniczenie dla całej zawartości w niestandardowej komórce widoku tabeli, a następnie oszacuj wysokość wiersza widoku tabeli i ustaw wysokość wiersza na automatyczny wymiar z wczytywaniu viewdid:
Aby rozwiązać ten problem z początkowym ładowaniem, zastosuj metodę layoutIfNeeded w niestandardowej komórce widoku tabeli:
źródło
estimatedRowHeight
wartość> 0, a nieUITableViewAutomaticDimension
(czyli -1), w przeciwnym razie automatyczna wysokość wiersza nie będzie działać.Wypróbowałem większość odpowiedzi na to pytanie i żadna z nich nie zadziałała. Jedynym funkcjonalnym rozwiązaniem, jakie znalazłem, było dodanie następujących elementów do mojej
UITableViewController
podklasy:UIView.performWithoutAnimation
Połączenie jest konieczne, w przeciwnym razie pojawi się normalny animacji widoku tabeli jako ładunku widok kontrolera.źródło
viewWillAppear
nie działało na mnie, ale robienie tego wviewDidAppear
nie.Ustawienie
preferredMaxLayoutWidth
pomaga w moim przypadku. dodałemw moim kodzie.
Zobacz także tekst jednowierszowy zajmuje dwie linie w UILabel i http://openradar.appspot.com/17799811 .
źródło
dzwonienie do
cell.layoutIfNeeded()
środkacellForRowAt
działało dla mnie na iOS 10 i iOS 11, ale nie na iOS 9.aby dostać tę pracę również na ios 9, dzwonię
cell.layoutSubviews()
i załatwiło sprawę.źródło
Dla mnie żadne z tych podejść nie zadziałało, ale odkryłem, że etykieta ma wyraźny
Preferred Width
zestaw w Interface Builder. Usunięcie tego (odznaczenie „Explicit”), a następnie użycieUITableViewAutomaticDimension
działało zgodnie z oczekiwaniami.źródło
Wypróbowałem wszystkie rozwiązania na tej stronie, ale odznaczenie klas wielkości i ponowne sprawdzenie rozwiązało mój problem.
Edycja: odznaczenie klas wielkości powoduje wiele problemów w scenorysie, więc wypróbowałem inne rozwiązanie. Zapełniłem widok tabeli w kontrolerze widoku
viewDidLoad
iviewWillAppear
metodach. To rozwiązało mój problem.źródło
Mam problem ze
zmianą rozmiaru etykiety, więc po skonfigurowaniu tekstu muszę po prostu zrobić chatTextLabel.text = chatMessage.message chatTextLabel? .UpdateConstraints ()
// pełny kod
źródło
W moim przypadku aktualizowałem w innym cyklu. Więc tableViewCell wysokość została zaktualizowana po ustawieniu labelText. Usunąłem blok asynchroniczny.
źródło
Tylko upewnij się, że nie ustawiasz tekstu etykiety w metodzie delegata „willdisplaycell” widoku tabeli. Ustaw tekst etykiety w metodzie delegata „cellForRowAtindexPath” na potrzeby dynamicznego obliczania wysokości.
Nie ma za co :)
źródło
W moim przypadku problem powodował widok stosu w komórce. Najwyraźniej to błąd. Po usunięciu problem został rozwiązany.
źródło
Problem polega na tym, że początkowe komórki ładują się, zanim uzyskamy prawidłową wysokość wiersza. Sposób obejścia problemu polega na wymuszeniu ponownego załadowania tabeli, gdy pojawi się widok.
źródło
Tylko dla iOS 12+, od 2019 r ...
Ciągły przykład sporadycznej, dziwacznej niekompetencji Apple, w której problemy trwają dosłownie latami.
Wydaje się, że tak jest
naprawi to. (Oczywiście tracisz trochę wydajności).
Takie jest życie z Apple.
źródło
W moim przypadku problem z wysokością komórki ma miejsce po załadowaniu początkowego widoku tabeli i wykonaniu akcji użytkownika (dotknięcie przycisku w komórce, która ma wpływ na zmianę wysokości komórki). Nie udało mi się zmusić komórki do zmiany jej wysokości, chyba że:
Próbowałem
ale to nie zadziałało.
źródło
W Swift 3. musiałem wywołać funkcję self.layoutIfNeeded () za każdym razem, gdy aktualizowałem tekst komórki wielokrotnego użytku.
źródło
Żadne z powyższych rozwiązań nie zadziałało, ale następująca kombinacja sugestii nie zadziałała.
Musiał dodać następujące elementy w viewDidLoad ().
Powyższa kombinacja reloadData, setNeedsLayout i layoutIfNeeded zadziałała, ale żadna inna. Może jednak być specyficzny dla komórek w projekcie. I tak, musiałem dwukrotnie wywołać reloadData, aby działało.
Ustaw również następujące elementy w viewDidLoad
W tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
źródło
reloadData/beginUpdates/endUpdates/reloadData
też działa;reloadData
musi zostać wezwany po raz drugi. Nie musisz go zawijaćasync
.Natknąłem się na ten problem i naprawiłem go, przenosząc kod inicjalizacji widoku / etykiety Z
tableView(willDisplay cell:)
DOtableView(cellForRowAt:)
.źródło
willDisplay
będzie miał lepszą wydajność niżcellForRowAt
. Użyj ostatniej tylko do zainicjowania właściwej komórki.willDisplay
masz lepszą wydajność, zaleca się zainicjowanie interfejsu użytkownika komórki,cellForRowAt
gdy układ jest automatyczny. Rzeczywiście, układ jest obliczany przez UIKit po cellForRowAt et przed willDisplay. Jeśli więc wysokość komórki zależy od jej zawartości, zainicjuj zawartość etykiety (lub cokolwiek) wcellForRowAt
.użyj powyższej metody, która dynamicznie zwraca wysokość wiersza. I przypisz tę samą dynamiczną wysokość do używanej etykiety.
Ten kod pomaga znaleźć dynamiczną wysokość tekstu wyświetlanego na etykiecie.
źródło