2014-07-15 11 views
34

Gdy użytkownik kliknie przycisk w jednym z moich wierszy, aktualizuję model bazowy dla tego wiersza, a następnie wywołuję metodę reloadRowsAtIndexPaths dla danego wiersza (to jest przeładowanie pojedynczego wiersza).UITableView odbija się w górę sekcji podczas wywoływania reloadRowsAtIndexPaths

- (IBAction)handleCompleteTouchEvent:(UIButton *)sender { 
    NSIndexPath *indexPath = [self.tableView indexPathForView:sender]; 
    id item = [self dataForIndexPath:indexPath]; 

    if ([item respondsToSelector:@selector(completed)]) { 
     // toogle completed value 
     BOOL completed = ![[item valueForKey:@"completed"] boolValue]; 
     [item setValue:[NSNumber numberWithBool:completed] forKey:@"completed"]; 

     [self.tableView beginUpdates]; 
     [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 
     [self.tableView endUpdates]; 
    } 
} 

Problem polega na tym, że widok tabeli po zakończeniu wywołania powraca na górę sekcji. Jak mogę temu zapobiec i zachować pozycję przewijania tam, gdzie jest?

+0

Kod wygląda OK. Czy możesz udostępnić więcej kodu, który może mieć związek z problemem? Czy jest jakieś miejsce w kodzie, jeśli kontroler widoku nazywa się '[self.tableView reloadData];? – Keenle

+0

Dodałem więcej kodu, aby pokazać całą metodę. Po wywołaniu reloadRowsAtIndexPaths tabela automatycznie przewija do góry sekcji, ale tylko wtedy, gdy nagłówek sekcji jest poza ekranem. Nie ma nic szczególnego w tworzeniu komórki lub nagłówku sekcji (tylko ciąg). – xsee

+0

@Keenle Nie wykonuję żadnych ponownych załadowań danych ani niczego w tym stylu. Ponadto, w dokumentacji nie ma nic o odbijaniu się do górnej części sekcji reloadRows. Nigdy wcześniej nie zauważyłem tej funkcjonalności, ale z drugiej strony zazwyczaj nie mam danych zmieniających działania w samej komórce, więc jest to dla mnie nowy rodzaj interakcji. – xsee

Odpowiedz

41

Ah Ha! Znalazłem problem i zamierzam odpowiedzieć na moje własne pytanie dla biednej duszy, która natknie się na tę kwestię w przyszłości.

Wszystkie moje komórki mają zmienną wysokość tak, byłem przy użyciu nowej metody iOS7 w UITableViewDelegate myślenia może przyspieszyć renderowanie czas (nie, że tak naprawdę to potrzebne):

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath; 

Zresztą, wdrażanie metoda ta ma zło skutkiem ubocznym powodując tabeli odbić do góry sekcji dzwoniąc:

[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 

aby rozwiązać ten problem odrzuceń po prostu usuwa nadpisanie tej metody estimatedHeightForRowAtIndexPath i teraz wszystko działa tak jak powinno. Zadowolony nareszcie.

+0

Dziękuję bardzo! Używanie "self.tableView.estimatedRowHeight" powodowało odskakiwanie widoku tabeli w moim przypadku. –

+2

Witaj, jeśli widzę, jeśli używam AutoLayout, jeśli nie używam extimatedRowHeight, to po dodaniu będzie problem, a wiersze będą się zmniejszać. – Ranjit

+0

Zaoszczędziłeś mnóstwo mojego czasu. Wielkie dzięki! –

3

Powinieneś być w stanie zrobić to, co chcesz zrobić, bezpośrednio zmieniając zawartość komórki. Na przykład, jeśli używasz podstawowej klasy UITableViewCell, a dane w twoim modelu to NSString, które wyświetlasz w komórce widoku tabeli, możesz wykonać następujące czynności (po zmianie modelu danych) zamiast dzwonić pod numer reloadRowsAtIndexPaths:

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 
UILabel *label = [cell textLabel]; 
label.text = @"New Value"; 

Jeśli używasz niestandardowej podklasy obiektu UITableViewCell, jest ona mniej więcej taka sama, z wyjątkiem tego, że dostęp do widoków komórki będzie musiał zostać wykonany za pośrednictwem właściwości contentView.

+1

To rozwiązanie działa, ale mi się nie podoba. Wyobraź sobie, że chcę wyrzucić cały prototyp komórki na podstawie zmiany modelu danych. Nie byłbym w stanie tego zrobić bez ponownego ładowania wiersza, ale potem wracam do kwadratu z problemem "Odbijanie do początku sekcji". Jeśli nie mogę uzyskać lepszej odpowiedzi (lub obejścia) problemu z ponownym załadowaniem, zaakceptuję tę odpowiedź. Dzięki. – xsee

2

To może być możliwe umieszczenie komórki w jego własnej sekcji sekcja i wezwanie reload:

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade]; 

wydaje się częściowo rozwiązać ten problem. Nie najczystszy sposób, ale może ci pomóc.

1

W moim podobnym przypadku, miałem do dostrojenia wdrażania metody

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
... 
} 

gdzie moi wysokości były zresetowane. Dlatego zamiast resetowania wysokości dla każdej komórki zaktualizowałem tylko wywoływane komórki dla wywołania reloadRowsAtIndexPaths.

0

Jeśli znasz minimalną wysokość komórki, musisz określić ją podczas ustawiania estimatedRowHeight. Ustawiłem go na 1, jak już wcześniej przeczytałem, że każda wartość powyżej 0 wystarczyłaby do celu, ale to był winowajca.

Kiedy ustawiłem na 44, co było minimalną wysokością, jaką mogła mieć moja komórka, wszystko poszło dobrze.

Dynamiczne wysokości również działały bez problemów z tą poprawką.

Powiązane problemy