2012-07-07 6 views
5

Chcę użyć ix 5, by wykonać animowane ruchy wiersza, aby animować widok tabeli w celu dopasowania niektórych zmian stanu modelu, zamiast starszego stylu usuwania i wstawić.UITableView: using moveRowAtIndexPath: toIndexPath: i reloadRowsAtIndexPaths: withRowAnimation: razem pojawią się zepsute

Zmiany mogą obejmować zarówno zmianę kolejności, jak i aktualizacje w miejscu, a ja chcę animować oba, więc niektóre wiersze będą wymagać reloadRowsAtIndexPaths.

Ale! UITableView wydaje się po prostu niewłaściwy w obsłudze przeładunków rzędów w obecności ruchów, jeśli zaktualizowana komórka przesuwa pozycję z powodu ruchów. Używanie starszych poleceń delete + insert, w sposób, który powinien być równoważny, działa dobrze.

Oto kod; Przepraszam za gadatliwość, ale kompiluje i działa. Mięso jest w metodzie doMoves:. Ekspozycja poniżej.

#define THISWORKS 

@implementation ScrambledList // extends UITableViewController 
{ 
    NSMutableArray *model; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    model = [NSMutableArray arrayWithObjects: 
      @"zero", 
      @"one", 
      @"two", 
      @"three", 
      @"four", 
      nil]; 
    [self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle: 
#ifdef THISWORKS 
               @"\U0001F603" 
#else 
               @"\U0001F4A9" 
#endif 
                       style:UIBarButtonItemStylePlain 
                      target:self 
                      action:@selector(doMoves:)]]; 
} 

-(IBAction)doMoves:(id)sender 
{ 
    int fromrow = 4, torow = 0, changedrow = 2; // 2 = its "before" position, just like the docs say. 

    // some model changes happen... 
    [model replaceObjectAtIndex:changedrow 
        withObject:[[model objectAtIndex:changedrow] stringByAppendingString:@"\u2032"]]; 
    id tmp = [model objectAtIndex:fromrow]; 
    [model removeObjectAtIndex:fromrow]; 
    [model insertObject:tmp atIndex:torow]; 

    // then we tell the table view what they were 
    [self.tableView beginUpdates]; 
    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:changedrow inSection:0]] 
         withRowAnimation:UITableViewRowAnimationRight]; // again, index for the "before" state; the tableview should figure out it really wants row 3 when the time comes 
#ifdef THISWORKS 
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:fromrow inSection:0]] 
         withRowAnimation:UITableViewRowAnimationAutomatic]; 
    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:torow inSection:0]] 
         withRowAnimation:UITableViewRowAnimationAutomatic]; 
#else // but this doesn't 
    [self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:fromrow inSection:0] 
         toIndexPath:[NSIndexPath indexPathForRow:torow inSection:0]]; 
#endif 
    [self.tableView endUpdates]; 
} 

#pragma mark - Table view data source boilerplate, not very interesting 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return model.count; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@""]; 
    if (cell == nil) 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@""]; 
    [cell.textLabel setText:[[model objectAtIndex:indexPath.row] description]]; 
    [cell.detailTextLabel setText:[NSString stringWithFormat:@"this cell was provided for row %d", indexPath.row]]; 
    return cell; 
} 

Co robi kod: ustawia mały model (mała zmienna tablica); po naciśnięciu przycisku następuje niewielka zmiana środkowego elementu listy i przeniesienie ostatniego elementu jako pierwszego. Następnie aktualizuje widok tabeli, aby odzwierciedlić te zmiany: ponownie wczytuje środkowy wiersz, usuwa ostatni wiersz i wstawia nowy wiersz zero.

To działa. W rzeczywistości dodanie loginu do cellForRowAtIndexPath pokazuje, że chociaż pytam o ponowne załadowanie wiersza 2, widok tabeli prawidłowo prosi o wiersz 3 z powodu wstawienia, gdy nadejdzie czas, aby faktycznie wykonać aktualizację. Huzzah!

Teraz skomentuj górne #ifdef, aby użyć wywołania moveRowAtIndexPath.

Teraz tableview usuwa Row 2, prosi o świeżej rzędu (źle!), I wstawia go w ostatnim rzędzie, 2 stanowiska (także źle!). Wynik netto jest taki, że wiersz 1 przesunął się w dół o dwa gniazda zamiast jednego, a przewijanie go poza ekranem, aby wymusić ponowne załadowanie, pokazuje, jak zsynchronizowano to z modelem. Mogłem zrozumieć, czy moveRowAtIndexPath zmienił model prywatny widoku tabeli w innej kolejności, wymagając użycia "nowych" zamiast "starych" ścieżek indeksu w przeładowaniach lub pobraniach modelu, ale to nie jest to, co się dzieje. Zauważ, że w drugim "po" picu, trzeci i czwarty wiersz są w odwrotnej kolejności, co nie powinno się zdarzyć bez względu na to, którą komórkę przeładowuję.

before state

after one button push, delete-insert style

after one button push, move-style

Moje słownictwo wzrosła kolorowe cursing Apple. Czy zamiast tego powinienem przeklinać siebie? Czy ruchy wiersza są po prostu niekompatybilne z przeładowaniami wierszy w tym samym bloku aktualizacji (jak również, podejrzewam, wstawia i usuwa)? Czy ktoś może mnie oświecić, zanim przejdę do zgłoszenia błędu?

+0

Bardzo interesujące! –

+0

Czy kiedykolwiek znalazłeś rozwiązanie tego problemu? Wpisuję dokładnie ten sam problem. –

+0

Nie! Złożyłem raport o błędzie, który został zamknięty z "niewystarczającą ilością informacji" i prośbą o przetestowanie go pod ios6 (do którego nie dotarłem, ale jeśli masz problem, prawdopodobnie nie został on naprawiony, a UICollectionView może mieć podobny problem.) Dwa obejścia, których oczekuję, to: wykonaj dwa oddzielne bloki begin/endUpdates, jeden do przeładowania, a drugi do ruchów/insertów/usunięć; lub całkowicie pominąć ponowne załadowanieRowsAtIndexPaths i zlokalizować/ponownie zaludnić odpowiednie komórki ręcznie. – rgeorge

Odpowiedz

3

Po prostu spędziłem trochę czasu bawiąc się twoim kodem i zgadzam się; wygląda na to, że to po prostu nie działa.

Cały ten obszar jest nieco niedostatecznie udokumentowany, ale w rzeczywistości nie mówią, że można mieszać moveRowAtIndexPath:toIndexPath: za pomocą metod ponownego ładowania. It ma powiedzieć, że można go mieszać z metody wstawiania wierszy i usuwanie wierszy. Wydaje się, że działają, jeśli zmienię Twój kod, aby je wykonywać. Tak więc możesz poprosić o ulepszenie, nie zgłaszając błędu. Tak czy siak, zdecydowanie wyślę to na radarze.

+0

Dzięki za potwierdzenie. Radar złożył. Jeśli Apple kiedykolwiek to rozwiąże, dołączę postanowienie. – rgeorge

Powiązane problemy