wake-up-neo.com

iOS 8 Auto cell height - Kann nicht bis zur letzten Zeile scrollen

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?

So können Sie das Problem wiederherstellen:

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

56
BenB

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:

  1. Wenn Sie eine große geschätzte Zeilenhöhe verwenden, wird beim Scrollen zur letzten Zeile mit Animation die Zellen der Tabellensicht ausgeblendet.
  2. Wenn Sie eine kleine geschätzte Zeilenhöhe verwenden, führt das Scrollen zur letzten Zeile mit Animation dazu, dass das Scrollen zu früh beendet wird und einige Zellen unterhalb des sichtbaren Bereichs (und der letzten Zeile außerhalb des Bildschirms) verbleiben.

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.

32
smileyborg

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.

20
abinop

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)
        })
    }
13
Bhavesh Tiwari

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.

4

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!

1
Marcus

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

0

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.

0
Stefan Olaru

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.

enter image description hereenter image description here

0
kendotwill

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);
}
0
ypresto

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)
        }
            }
0
Bibin Joseph

Rufen Sie einfach tableview reloadData auf, nachdem viewDidAppear das Problem lösen kann

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self.tableView reloadData];
}
0
Evan JIANG