UITableView dynamiczne wysokości komórek poprawiają się tylko po przewinięciu
Mam UITableView
z niestandardowym UITableViewCell
zdefiniowanym w storyboardzie za pomocą układu automatycznego. Komórka posiada kilka multilinii UILabels
.
UITableView
wydaje się prawidłowo obliczać wysokość komórek, ale dla pierwszych kilku komórek wysokość ta nie jest odpowiednio podzielona między etykiety.
Po trochę przewinięciu wszystko działa zgodnie z oczekiwaniami (nawet komórki, które początkowo były nieprawidłowe).
- (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 pierwsze kilka razy?
Stworzyłem przykładowy projekt , który demonstruje to zachowanie.
22 answers
Nie wiem, czy jest to wyraźnie udokumentowane, czy nie, ale dodanie [cell layoutIfNeeded]
przed zwróceniem komórki rozwiązuje twój problem.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"];
NSUInteger n1 = firstLabelWordCount[indexPath.row];
NSUInteger n2 = secondLabelWordCount[indexPath.row];
[cell setNumberOfWordsForFirstLabel:n1 secondLabel:n2];
[cell layoutIfNeeded]; // <- added
return cell;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-22 09:58:36
Dodawanie [cell layoutIfNeeded]
w cellForRowAtIndexPath
nie działa w przypadku komórek, które są początkowo przewijane poza widok.
Nie ma też przedruku z [cell setNeedsLayout]
.
Nadal musisz przewijać niektóre komórki na zewnątrz i z powrotem do widoku, aby poprawnie zmienić ich rozmiar.
Jest to dość frustrujące, ponieważ większość deweloperów ma dynamiczny Typ, AutoLayout i Samorozmiarowe komórki działające poprawnie-z wyjątkiem tego irytującego przypadku. Ten błąd wpływa na wszystkie moje" wyższe " Kontrolery widoku tabeli.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-25 13:20:03
To działało dla mnie, gdy inne podobne rozwiązania nie:
override func didMoveToSuperview() {
super.didMoveToSuperview()
layoutIfNeeded()
}
Wydaje się to prawdziwym błędem, ponieważ jestem bardzo zaznajomiony z AutoLayout i jak używać UITableViewAutomaticDimension, jednak nadal czasami natykam się na ten problem. Cieszę się, że w końcu znalazłem coś, co działa jako obejście.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-27 09:15:16
Miałem takie samo doświadczenie w jednym z moich projektów.
Dlaczego tak się dzieje?
Komórka zaprojektowana w Storyboardzie z pewną szerokością dla jakiegoś urządzenia. Na przykład 400px. Na przykład etykieta ma taką samą szerokość. Gdy ładuje się z storyboard, ma szerokość 400px.
Oto problem:
tableView:heightForRowAtIndexPath:
wywołane przed układem komórki To podwidywacze.
Obliczono więc wysokość dla etykiety i komórki o szerokości 400px. Ale uruchamiasz na urządzeniu z Ekranem, na przykład 320px. I to wysokość obliczana automatycznie jest nieprawidłowa. Tylko dlatego, że cell ' s layoutSubviews
dzieje się dopiero po tableView:heightForRowAtIndexPath:
Nawet jeśli ręcznie ustawisz preferredMaxLayoutWidth
dla swojej etykiety w layoutSubviews
, to nie pomaga.
Moje rozwiązanie:
1) podklasa UITableView
i nadpisanie dequeueReusableCellWithIdentifier:forIndexPath:
. Ustaw szerokość komórki równą szerokości tabeli i Wymuś jej układ.
- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
CGRect cellFrame = cell.frame;
cellFrame.size.width = self.frame.size.width;
cell.frame = cellFrame;
[cell layoutIfNeeded];
return cell;
}
2) podklasa UITableViewCell
.
Ustaw ręcznie preferredMaxLayoutWidth
dla etykiet w layoutSubviews
. Trzeba również ręcznie layout contentView
, ponieważ nie układa się automatycznie po zmianie ramki komórki (I Nie wiem dlaczego, ale jest)
- (void)layoutSubviews {
[super layoutSubviews];
[self.contentView layoutIfNeeded];
self.yourLongTextLabel.preferredMaxLayoutWidth = self.yourLongTextLabel.width;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-28 21:54:47
Mam podobny problem, przy pierwszym ładowaniu wysokość wiersza nie została obliczona, ale po pewnym przewinięciu lub przejściu do innego ekranu i wracam do tego ekranu wiersze są obliczane. Przy pierwszym ładowaniu moje pozycje są ładowane z Internetu, a przy drugim ładowaniu moje pozycje są ładowane najpierw z podstawowych danych i przeładowywane z Internetu i zauważyłem, że wysokość wierszy jest obliczana przy przeładowaniu z Internetu. Więc zauważyłem, że kiedy tableView.reloadData() jest wywoływana podczas animacji segue (ta sama problem z push I present segue), wysokość wiersza nie została obliczona. Więc ukryłem tableview w widoku inicjalizacji i umieścić activity loader, aby zapobiec brzydki efekt dla użytkownika i wywołuję tableView.przeładuj dane po 300ms i teraz problem jest rozwiązany. Myślę, że to błąd UIKit, ale to obejście robi sztuczkę.
I umieścić te linie (Swift 3.0) w moim item Load completion handler
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute: {
self.tableView.isHidden = false
self.loader.stopAnimating()
self.tableView.reloadData()
})
To wyjaśnia, dlaczego dla niektórych osób, umieścić reloadData w layoutSubviews rozwiązać wydanie
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-26 21:11:00
W moim przypadku ostatnia linia UILabel została obcięta, gdy komórka była wyświetlana po raz pierwszy. Stało się to dość losowo, a jedynym sposobem na poprawny rozmiar było przewinięcie komórki z widoku i przywrócenie jej. Próbowałem wszystkich możliwych rozwiązań wyświetlanych do tej pory (layoutIfNeeded..reloadData) ale u mnie nic nie działało. Sztuczka polegała na ustawieniu "Autoshrink" na Minimuum Font Scale (dla mnie 0.5). Spróbuj
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-01 13:36:38
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 ładowaniem widoku:
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 70
tableView.rowHeight = UITableViewAutomaticDimension
}
Aby naprawić początkowy problem z ładowaniem, zastosuj metodę layoutIfNeeded z w niestandardowej komórce widoku tabeli:
class CustomTableViewCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
self.layoutIfNeeded()
// Initialization code
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-08 16:21:33
Próbowałem większości odpowiedzi na to pytanie i nie mogłem zmusić żadnej z nich do pracy. Jedynym funkcjonalnym rozwiązaniem, jakie znalazłem, było dodanie do mojej UITableViewController
podklasy:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIView.performWithoutAnimation {
tableView.beginUpdates()
tableView.endUpdates()
}
}
Wywołanie UIView.performWithoutAnimation
jest wymagane, w przeciwnym razie zobaczysz normalną animację widoku tabeli podczas ładowania kontrolera widoku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-30 19:44:01
Ustawienie preferredMaxLayoutWidth
pomaga w moim przypadku.
Dodałem
cell.detailLabel.preferredMaxLayoutWidth = cell.frame.width
W moim kodzie.
Zobacz także tekst w jednej linii zawiera dwie linie w UILabel i http://openradar.appspot.com/17799811 .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:31
Próbowałem wszystkich rozwiązań na tej stronie, ale odznaczenie użyj klas rozmiaru, a następnie sprawdzenie go ponownie rozwiązało mój problem.
Edit: odznaczanie klas wielkości powoduje wiele problemów na storyboardzie, więc próbowałem innego rozwiązania. Wypełniłem tableView w metodzie kontrolera widoku ViewDidLoad
i ViewWillAppear
. To rozwiązało mój problem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-25 16:26:11
dla mnie żadne z tych podejść nie zadziałało, ale odkryłem, że etykieta ma wyraźny Preferred Width
ustawiony w Kreatorze interfejsów. Usunięcie tego (odznaczenie "Explicit") i użycie UITableViewAutomaticDimension
działało zgodnie z oczekiwaniami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-03 16:22:11
Mam problem ze zmianą rozmiaru etykiety więc muszę to zrobić
chatTextLabel.text = "chatMessage",wiadomość
chatTextLabel?.updateConstraints () po ustawieniu tekstu
// Pełny kod
func setContent() {
chatTextLabel.text = chatMessage.message
chatTextLabel?.updateConstraints()
let labelTextWidth = (chatTextLabel?.intrinsicContentSize().width) ?? 0
let labelTextHeight = chatTextLabel?.intrinsicContentSize().height
guard labelTextWidth < originWidth && labelTextHeight <= singleLineRowheight else {
trailingConstraint?.constant = trailingConstant
return
}
trailingConstraint?.constant = trailingConstant + (originWidth - labelTextWidth)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-20 13:54:41
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
// call the method dynamiclabelHeightForText
}
Użyj powyższej metody, która dynamicznie Zwraca wysokość wiersza. I przypisać tę samą dynamiczną wysokość do używanej etykiety.
-(int)dynamiclabelHeightForText:(NSString *)text :(int)width :(UIFont *)font
{
CGSize maximumLabelSize = CGSizeMake(width,2500);
CGSize expectedLabelSize = [text sizeWithFont:font
constrainedToSize:maximumLabelSize
lineBreakMode:NSLineBreakByWordWrapping];
return expectedLabelSize.height;
}
Ten kod pomaga znaleźć dynamiczną wysokość wyświetlania tekstu na etykiecie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-25 13:20:30
W moim przypadku problem z wysokością komórki ma miejsce po załadowaniu początkowego widoku tabeli i wykonaniu czynności użytkownika(dotknięcie przycisku w komórce, który ma wpływ na zmianę wysokości komórki). Nie udało mi się zmusić komórki do zmiany wysokości chyba, że to zrobię:
[self.tableView reloadData];
I did try
[cell layoutIfNeeded];
Ale to nie zadziałało.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-04 20:23:05
W Swift 3. Musiałem zadzwonić do siebie.layoutIfNeeded() za każdym razem aktualizuję tekst komórki wielokrotnego użytku.
import UIKit
import SnapKit
class CommentTableViewCell: UITableViewCell {
static let reuseIdentifier = "CommentTableViewCell"
var comment: Comment! {
didSet {
textLbl.attributedText = comment.attributedTextToDisplay()
self.layoutIfNeeded() //This is a fix to make propper automatic dimentions (height).
}
}
internal var textLbl = UILabel()
override func layoutSubviews() {
super.layoutSubviews()
if textLbl.superview == nil {
textLbl.numberOfLines = 0
textLbl.lineBreakMode = .byWordWrapping
self.contentView.addSubview(textLbl)
textLbl.snp.makeConstraints({ (make) in
make.left.equalTo(contentView.snp.left).inset(10)
make.right.equalTo(contentView.snp.right).inset(10)
make.top.equalTo(contentView.snp.top).inset(10)
make.bottom.equalTo(contentView.snp.bottom).inset(10)
})
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let comment = comments[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: CommentTableViewCell.reuseIdentifier, for: indexPath) as! CommentTableViewCell
cell.selectionStyle = .none
cell.comment = comment
return cell
}
commentsTableView.rowHeight = UITableViewAutomaticDimension
commentsTableView.estimatedRowHeight = 140
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 06:51:59
W moim przypadku aktualizowałem w innym cyklu. Tak więc wysokość tableViewCell została zaktualizowana po ustawieniu labelText. Usunąłem blok asynchroniczny.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:Identifier, for: indexPath)
// Check your cycle if update cycle is same or not
// DispatchQueue.main.async {
cell.label.text = nil
// }
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-04 05:52:14
Żadne z powyższych rozwiązań nie zadziałało, ale następująca kombinacja sugestii nie zadziałała.
Musiałem dodać następujące elementy w viewDidLoad ().
DispatchQueue.main.async {
self.tableView.reloadData()
self.tableView.setNeedsLayout()
self.tableView.layoutIfNeeded()
self.tableView.reloadData()
}
Powyższa kombinacja reloadData, setNeedsLayout i layoutIfNeeded zadziałała, ale żadna inna. Może to być specyficzne dla komórek w projekcie. I tak, musiałem dwukrotnie wywołać reloadData, aby to działało.
Ustaw również następujące opcje w viewDidLoad
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = MyEstimatedHeight
In tableView (_tableView: UITableView, cellForRowAt indexPath: IndexPath)
cell.setNeedsLayout()
cell.layoutIfNeeded()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-22 15:17:55
Upewnij się tylko, że nie ustawiasz tekstu etykiety w metodzie' willdisplaycell ' w widoku tabeli. Ustaw tekst etykiety w metodzie' cellForRowAtindexPath ' do dynamicznego obliczania wysokości.
Zapraszam:)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-25 06:12:15
W moim przypadku problem powodował widok stosu w komórce. Najwyraźniej to robak. Gdy go usunąłem, problem został rozwiązany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-26 10:53:11
Napotkałem ten problem i naprawiłem go, przenosząc mój kod inicjalizacji widoku/etykiety z tableView(willDisplay cell:)
na tableView(cellForRowAt:)
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-12 03:18:06
Problem polega na tym, że początkowe komórki ładują się przed uzyskaniem prawidłowej wysokości wiersza. Obejście polega na wymuszeniu przeładowania tabeli, gdy pojawi się widok.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView reloadData];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-20 13:44:49
Na ios 10 i ios 11 zadziałało, ale nie na ios 9.
Aby uzyskać tę pracę również na ios 9, dzwonię cell.layoutSubviews()
i udało się.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-28 17:02:23