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ę.
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?
Bardzo interesujące! –
Czy kiedykolwiek znalazłeś rozwiązanie tego problemu? Wpisuję dokładnie ten sam problem. –
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