2013-06-07 14 views
5

Używam ponownie nagłówków, zachowując je w słowniku, gdzie numer sekcji jest kluczowy, a widok nagłówka jest wartością.Ramka widoku nagłówka zmieniana na zawsze po usunięciu sekcji UITableView o numerze

Po animacji usuniętej jednej sekcji i ponownym wczytaniu kolejnej, widoki nagłówków tylko tych sekcji "zniknęły". Po kilku poszukiwaniach okazało się, że zmieniono ramki tych widoków nagłówka. Frame.X widoku nagłówka z sekcji, która została usunięta z przesunięciem UITableViewRowAnimationRight na szerokość ekranu po prawej (320), i tej, która została zmieniona na UITableViewRowAnimationAutomatic przesunięta o Y.

Główny problem i zamieszanie wynika z faktu, że nie mogę zmienić tych ramek! Cóż, początkowo się zmieniają, ale nic nie zmienia się wizualnie, a z drugiej strony ramki są ponownie przesuwane.

Oto jak to zrobić:

Załóżmy, że mamy 3 sekcji z danymi każdego leży w jednej z tablic _first, _second i _third. I przez touchupinside przycisku dzwonimy pod numer handleTouchUp:. (_second pozostaje niezmieniona)

- (void) handleTouchUp: (UIButton *)sender 
{ 
    if ([_first count] == 0) { 
     sectionCount = 3; 
     _first = [NSMutableArray arrayWithObjects: @"First 1", @"First 2", nil]; 
     _third = [NSMutableArray arrayWithObjects: @"Third 1", @"Third 2", @"Third 3", @"Third 4", @"Third 5", nil]; 
     [tableView reloadData]; 
    } else { 
     sectionCount = 2; 
     [_first removeAllObjects]; 
     _third = [NSMutableArray arrayWithObjects: @"First 1", @"First 2", @"Third 1", @"Third 2", 
                @"Third 3", @"Third 4", @"Third 5", nil]; 
     [tableView beginUpdates]; 
     [tableView deleteSections: [NSIndexSet indexSetWithIndex: 0] withRowAnimation:UITableViewRowAnimationRight]; 
     [tableView reloadSections: [NSIndexSet indexSetWithIndex: 2] withRowAnimation:UITableViewRowAnimationAutomatic]; 
     [tableView endUpdates]; 
    } 
} 


- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 
{ 
    NSNumber *key = [NSNumber numberWithInteger: section]; 
    UIView *header = [_headers objectForKey: key]; 
    if (header) { 

    } else { 
     header = [[UIView alloc] init]; 
     switch (section) { 
      //Doing something with header here (e.g. set background color) 
     } 
     [_headers setObject:header forKey: key]; 
    } 

    [header setFrame: CGRectMake(0, 0, 320, 25)]; 

    return header; 
} 

Here is full code of ViewController.m i test project

UPDATE: może istnieć kilka innych błędów w projekcie, ale to nie jest ważne - to projekt testowy. Jedyny ważny problem to nieprawidłowe widoki nagłówka. Usunięcie nieprawidłowego widoku i utworzenie nowego nie jest rozwiązaniem - zabija punkt ponownego wykorzystania widoków nagłówka.

Odpowiedz

3

Znalazłem kilka błędów w Twoim projekcie, które faktycznie doprowadziły do ​​pewnych awarii i uważam, że były również odpowiedzialne za błędy w widoku nagłówkowym, które widzisz w aplikacji. Po ich naprawieniu i aplikacja wydaje mi się właściwie działać.

Oto zaktualizowana wersja projektu: https://bitbucket.org/reydan/tableheaderviews

starałem się zachować jak najbardziej zbliżony do pierwotnego projektu, ale musiałem dokonać pewnych zmian. Jeśli uważasz, że nie pasuje on do pożądanej funkcjonalności, zostaw komentarz, a ja go zaktualizuję (to właśnie wydedukowałem, że projekt powinien się zachowywać). Wszystkie zmiany, które wyjaśniono poniżej, można również zobaczyć w tym zaktualizowanym projekcie.

Problemy, które znalazłem, dotyczyły faktu, że jeśli usuniesz sekcję z widoku tabeli, cała sekcja po niej zmieni swój indeks (z -1). Jest to normalne, ponieważ indeks sekcji jest tak naprawdę indeksem, a nie unikalnym kluczem przypisanym do każdej sekcji.

Po usunięciu pierwszej sekcji, trzecia sekcja miała teraz indeks = 1, a widok delegatów metod odczytuje dane niepoprawnie (w tym widoki nagłówków), ponieważ wszystko było oparte na indeksie sekcji.

Aby to naprawić, zmieniłem pamięć podręczną widoku nagłówka, aby używać tablic danych jako kluczy (_pierwszy, _second lub _third). Aby to ułatwić, stworzyłem metodę, która może wywoływać z wielu miejsc i zwraca poprawny tablicą danych na podstawie wskaźnika przekroju i bieżącej sekcji liczyć:

- (NSArray*)dataArrayForSection:(NSInteger)section 
{ 
    if (sectionCount == 3) 
    { 
     switch (section) 
     { 
      case 0: return _first; 
      case 1: return _second; 
      case 2: return _third; 
     } 
    } 
    else 
    { 
     switch (section) 
     { 
      case 0: return _second; 
      case 1: return _third; 
     } 
    } 

    return nil; 
} 

Teraz cache nagłówek korzysta z tablic danych jako klucze , ważne jest, aby usunąć wpisy nagłówka podczas ponownego przydzielania tablic w metodzie handleTouchUp.

- (void) handleTouchUp: (UIButton *)sender 
{ 
    NSLog(@"Touched!"); 
    if ([_first count] == 0) 
    { 
     sectionCount = 3; 

     // **INSERTED** Removes the cache for the _first and _third keys because you are recreating the arrays again, 
     // and so you are losing the initial key. Not doing this, results in a memory leak 
     [_headers removeObjectForKey:_first]; 
     [_headers removeObjectForKey:_third]; 

     _first = [NSMutableArray arrayWithObjects: @"First 1", @"First 2", nil]; 
     _third = [NSMutableArray arrayWithObjects: @"Third 1", @"Third 2", @"Third 3", @"Third 4", @"Third 5", nil]; 

     [tableView reloadData]; 
//  [tableView beginUpdates]; 
//  [tableView reloadSections: [NSIndexSet indexSetWithIndex: 0] withRowAnimation:UITableViewRowAnimationRight]; 
//  [tableView reloadSections: [NSIndexSet indexSetWithIndex: 2] withRowAnimation:UITableViewRowAnimationAutomatic]; 
//  [tableView endUpdates]; 
    } 
    else 

Kolejną rzeczą, którą poprawiłem, jest ponowne wykorzystanie komórek widoku tabeli. Powinieneś zawsze próbować i ponownie używać istniejących UITableViewCells (z kilkoma wyjątkami). cellForRowAtIndexPath teraz wygląda tak:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSArray* dataarray = [self dataArrayForSection:indexPath.section]; 


    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"my_text_cell"]; 
    if (cell == nil) 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"my_text_cell"]; 


    if (dataarray == nil) 
     cell.textLabel.text = @"default"; 
    else 
     cell.textLabel.text = [dataarray objectAtIndex:indexPath.row]; 


    return cell; 
} 

Jeśli masz jakieś pytania, proszę zostawić komentarz.

EDIT

Próbowałem zaktualizować projekt testowy według żądania, aby zachować pamięć podręczną w nienaruszonym stanie i jestem rzeczywiście w stanie odtworzyć błąd - po kasowania animacja/reload, nagłówek na ostatniej sekcji nie jest widoczny.

Odkryłem, że automatyczna animacja ponownego załadowania, którą wybiera iOS, to animacja zaniku. Powoduje to zanikanie widoku nagłówka. Przetestowałem to, dodając kolejny przycisk w aplikacji, który ustawia alfa = 1 dla wszystkich buforowanych widoków nagłówka. Po animacji przeładowania nacisnąłem ten przycisk, a widoki nagłówka ukazały się poprawnie.

Próbowałem używać innych animacji, ale nie wyglądały ładnie.

Podsumowując, nie sądzę, że Apple zaleca buforowanie widoków nagłówka. W dokumentacji, począwszy od iOS 6.0, jest nowa metoda, która rozwiązuje ten problem. Zachowuje się ono podobnie do komórek dequeueing, ale dla nagłówka poglądów/stopki
- (id)dequeueReusableHeaderFooterViewWithIdentifier:(NSString *)identifier

Tak więc, jeśli kierować iOS 6.0+ następnie można użyć zamiast tego ręcznie buforowanie nagłówki. W przeciwnym razie rozwiązanie, które znalazłem, polega na usunięciu z pamięci podręcznej tylko widoków nagłówka dla usuniętych i przeładowanych sekcji (_pierwszy i _tny).

I uaktualniony projekt, aby usunąć tylko ostatni nagłówek sekcji podczas odświeżania

+0

Chodziło rama nagłówek ten View staje się nieważny po animowanego delecji/reload. Wszystkie inne błędy (w tym ponowne użycie komórek) tak naprawdę nie mają znaczenia, ponieważ jest to tylko projekt testowy, który napisałem, aby pokazać problem z ramkami widoku nagłówka. Powodem, dla którego Twój projekt nie ma tego problemu, jest to, że zawsze odtwarzasz widoki nagłówków, na które miały wpływ animacje, a nie robi się tego całego punktu widoku nagłówkowego "pamięć podręczna". Również nie dostałem twojego komentarza o utracie klucza początkowego (tuż przed usunięciem nagłówka z pamięci podręcznej). – folex

+0

Ale w każdym razie, widok nagłówka nie powinien być przerwany po animacji, to po prostu niepoprawne. Jeśli chcę korzystać z tego samego widoku, powinienem móc użyć dokładnie tego samego widoku, jeśli nie jest on uszkodzony i jeśli widok ten pokazuje jeden raz w widoku hierarchii. Jeśli możesz, spróbuj nie wyczyścić pamięci podręcznej, a skończy się uszkodzonymi widokami. – folex

+0

Spróbuję i wyjaśnię lepiej, co mam na myśli przez niewłaściwe klucze. Masz zapisane w pamięci podręcznej widoki nagłówków dla kluczy 0,1,2. Kiedy usuniesz pierwszą sekcję (indeks = 0) i odświeżysz sekcję 2, to odświeżenie zostanie wywołane z indeksem = 1 - ponieważ pierwsza sekcja zniknęła, a wszystkie inne sekcje przesunięte o -1. Tak więc, w tym odświeżeniu nagłówka, w oparciu o twój kod zwrócony zostanie widok nagłówka z kluczem 1, ale ten dokładny uiview jest również używany do poprzedniej drugiej sekcji (która nie została odświeżona i zachowała stary widok nagłówka). Mając takie samo UIView w 2 miejscach, uważam, że powoduje problemy. –

Powiązane problemy