Ich verwende iOS 8 neue Zellen zur automatischen Größenanpassung. Optisch funktioniert es gut - jede Zelle bekommt die richtige Größe. Wenn ich jedoch versuche, bis zur letzten Zeile scrollen, scheint die Tabellenansicht die richtige Größe nicht zu kennen. Ist das ein Fehler oder gibt es eine Lösung dafür?
Mit diesem Projekt - TableViewCellWithAutoLayoutiOS8 (referenziert von dieser SO - Antwort ) erhielt ich die automatisch skalierbaren Zellen wie erwartet.
Wenn ich jedoch die Funktion scrollToRowAtIndexPath aufrufe, dann wie folgt:
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: model.dataArray.count - 1, inSection: 0), atScrollPosition: .Bottom, animated: true)
Ich komme nicht bis zur letzten Reihe - Es bringt mich nur auf halber Strecke.
Selbst wenn Sie versuchen, eine niedrigere Funktion wie diese zu verwenden:
tableView.setContentOffset(CGPointMake(0, tableView.contentSize.height - tableView.frame.size.height), animated: true)
Das Ergebnis ist nicht wie erwartet, es kommt nicht zum Ende. Wenn ich viele Male darauf klicke oder ein paar Sekunden warte, wird es irgendwann an die richtige Stelle kommen. Es scheint, dass tableView.contentSize.height nicht richtig eingestellt ist, so dass das iOS nicht weiß, wo sich die letzte Zelle befindet.
Würde mich über jede Hilfe freuen.
Vielen Dank
Update: 24. Juni 2015
Apple hat die meisten dieser Fehler ab iOS 9.0 SDK behoben. Alle Probleme wurden ab iOS 9 Beta 2 behoben, einschließlich Scrollen nach oben und unten in der Tabellenansicht ohne Animation und Aufrufen von reloadData
, während in der Mitte der Tabellenansicht gescrollt wird.
Hier sind die verbleibenden Probleme, die noch nicht behoben wurden:
Es wurde ein neuer Fehlerbericht (rdar: // 21539211) für diese Probleme beim Scrollen mit Animation eingereicht.
Originalantwort
Dies ist ein Apple-Fehler bei der Schätzung der Tabellenzeilenzeilenhöhe. Er besteht seit der Einführung dieser Funktionalität in iOS 7. Ich habe direkt mit Apple UIKit-Ingenieuren und Entwickler-Evangelisten an diesem Problem gearbeitet - sie haben bestätigt, dass es sich um ein Problem handelt Fehler, haben jedoch keine verlässliche Problemumgehung (dies bedeutet nicht, dass die Zeilenhöhenschätzung deaktiviert wird), und es schien kein besonderes Interesse an der Behebung des Problems zu bestehen.
Beachten Sie, dass der Fehler sich auf andere Weise manifestiert, beispielsweise wenn Sie Tabellensichtzellen verschwinden lassen, wenn Sie reloadData
aufrufen, während Sie teilweise oder vollständig nach unten scrollen (z. B. ist contentOffset.y
deutlich größer als 0).
Bei iOS 8-Zellen zur automatischen Größenanpassung ist die Schätzung der Zeilenhöhe von entscheidender Bedeutung. Apple muss sich also so schnell wie möglich mit diesem ASAP befassen.
Ich habe diese Ausgabe am 21. Oktober 2013 als Radar # 15283329 eingereicht. Bitte reichen Sie doppelte Fehlerberichte ein, damit Apple einen Fix priorisiert.
Sie können dieses einfache Beispielprojekt anhängen, um das Problem zu veranschaulichen. Es basiert direkt auf Apples eigenem Beispielcode.
Dies war ein sehr nerviger Fehler, aber ich glaube, ich habe eine dauerhafte Lösung gefunden, obwohl ich nicht genau erklären kann, warum.
Rufen Sie die Funktion nach einer winzigen (unbemerkten) Verzögerung auf:
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: model.dataArray.count - 1, inSection: 0), atScrollPosition: .Bottom, animated: true)
})
Sag mir, ob das auch für dich funktioniert.
Es ist definitiv ein Fehler von Apple. Ich habe auch dieses Problem. Ich habe dieses Problem durch Aufrufen der Methode "scrollToRowAtIndexPath" zweimal gelöst.
if array.count > 0 {
let indexPath: NSIndexPath = NSIndexPath(forRow: array.count - 1, inSection: 0)
self.tblView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
self.tblView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
})
}
Ich habe eine temporäre Problemumgehung gefunden, die hilfreich sein könnte, bis Apple die vielen Fehler, die uns plagen, behebt.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *text = [self findTextForIndexPath:indexPath];
UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:13];
CGRect estimatedHeight = [text boundingRectWithSize:CGSizeMake(215, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: font}
context:nil];
return TOP_PADDING + CGRectGetHeight(estimatedHeight) + BOTTOM_PADDING;
}
Das ist nicht perfekt, aber es hat meine Aufgabe erfüllt. Jetzt kann ich anrufen:
- (void)scrollToLastestSeenMessageAnimated:(BOOL)animated
{
NSInteger count = [self tableView:self.tableView numberOfRowsInSection:0];
if (count > 0) {
NSInteger lastPos = MAX(0, count-1);
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:lastPos inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated];
}
}
On viewDidLayoutSubviews
und findet die richtige Stelle am Boden (oder eine sehr nahe geschätzte Position).
Ich hoffe das hilft.
Für meinen Fall fand ich eine temporäre Problemumgehung, indem ich dem Programm keine geschätzte Zellenhöhe vorschlug. Dazu habe ich die folgende Methode in meinem Code auskommentiert:
- (CGFloat) tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
Beachten Sie jedoch, dass dies die Benutzererfahrung beeinträchtigen kann, wenn der Benutzer einen Bildlauf durchführt, wenn sich die Zellen stark voneinander unterscheiden. Für meinen Fall bisher kein merklicher Unterschied.
Ich hoffe es hilft!
Meine Lösung bestand darin, die Größe des Storyboards als Schätzung zu verwenden.
Also stattdessen:
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
Ich habe so etwas gemacht:
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
MyMessageType messageType = [self messageTypeForRowAtIndexPath:indexPath];
switch (messageType) {
case MyMessageTypeText:
return 45;
break;
case MyMessageTypeMaybeWithSomeMediaOrSomethingBiggerThanJustText:
return 96;
break;
default:
break;
}
}
Ich schreibe eine Chat-Tabellenansicht, daher ist es wahrscheinlich, dass viele meiner Zellen, insbesondere der Texttyp, größer als der in IB ist, insbesondere wenn die Chat-Nachricht sehr lang ist. Dies scheint eine ziemlich gute ... na ja ... Schätzung und das Scrollen nach unten kommt ziemlich nahe. Es scheint etwas schlechter zu sein, da das Scrollen länger wird, aber das ist vermutlich zu erwarten
Das gleiche Problem hatte ich beim Erstellen einer Chat-TableView mit unterschiedlicher Zellenhöhe. Ich rufe den folgenden Code in der Lebenszyklusmethode viewDidAppear () auf:
// First figure out how many sections there are
let lastSectionIndex = self.tableView.numberOfSections - 1
// Then grab the number of rows in the last section
let lastRowIndex = self.tableView.numberOfRowsInSection(lastSectionIndex) - 1
// Now just construct the index path
let pathToLastRow = NSIndexPath(forRow: lastRowIndex, inSection: lastSectionIndex)
// Make the last row visible
self.tableView.scrollToRowAtIndexPath(pathToLastRow, atScrollPosition: UITableViewScrollPosition.None, animated: true)
Bitte lassen Sie mich wissen, ob das auch für Sie funktioniert hat.
Klicken Sie im Storyboard-Fenster in einen leeren Bereich, um die Auswahl aller Ansichten aufzuheben. Klicken Sie anschließend auf die Ansicht mit der Tabellenansicht. Klicken Sie dann auf das Symbol Resolve Auto Layout Issue
und wählen Sie Reset to Suggested Constraints
aus.
Als smileyborgs Antwort es ist ein Fehler in iOS 8.x, sollte es auf allen Plattformen behoben werden, die Sie unterstützen ...
Um die Problemumgehung unter iOS9 zu umgehen, führen Sie den folgenden Trick ohne dispatch_async oder dispatch_after ..__ aus. Wird unter iOS 8.4 simuliert.
UPDATE: Das Aufrufen von (nur) layoutIfNeeded funktioniert nicht, wenn der View Controller durch einen Bildlauf durch UIPageViewController sichtbar wird. Verwenden Sie daher stattdessen layoutSubviews (oder möglicherweise setNeedsLayout + layoutIfNeeded).
// For iOS 8 bug workaround.
// See https://stackoverflow.com/a/33515872/1474113
- (void)scrollToBottomForPreiOS9
{
CGFloat originalY, scrolledY;
do {
// Lay out visible cells immediately for current contentOffset.
// NOTE: layoutIfNeeded does not work when hosting UIPageViewController is dragged.
[self.tableView layoutSubviews];
originalY = self.tableView.contentOffset.y;
[self scrollToBottom]; // Call -scrollToRowAtIndexPath as usual.
scrolledY = self.tableView.contentOffset.y;
} while (scrolledY > originalY);
}
Verwenden Sie diesen einfachen Code, um nach unten zu scrollen
var rows:NSInteger=self.tableName.numberOfRowsInSection(0)
if(rows > 0)
{
let indexPath = NSIndexPath(forRow: rows-1, inSection: 0)
tableName.scrollToRowAtIndexPath(indexPath , atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)
}
}
Rufen Sie einfach tableview reloadData auf, nachdem viewDidAppear das Problem lösen kann
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView reloadData];
}