2009-09-18 12 views
22

Moja aplikacja musi mieć komórki tabeli o zmiennej wysokości (ponieważ każda komórka tabeli różni się wysokością, a nie każda komórka musi mieć możliwość zmiany rozmiaru).Jak prawidłowo wykonać komórki tabeli o zmiennej wysokości na iPhonie?

Mam rozwiązanie, które obecnie działa, ale jest kludgy i powolne.

Moje obecne rozwiązanie:

Przed komórki tabeli są renderowane, obliczyć jak wysokie każda komórka musi być przez wywołanie metody wymiarowania takich jak -sizeWithFont:constrainedToSize: na jego danych. Następnie sumuję wysokości, pozwalam na dopełnienie i przechowuję wynik z danymi.

Kiedy mój UITableViewDelegate otrzyma -tableview:heightForRowAtIndexPath:, ustalam, który element zostanie wyrenderowany dla tej komórki i zwróci wysokość, którą obliczałem poprzednio.

Jak już powiedziałem, to działa, ale wywołanie -sizeWithFont:constrainedToSize: jest bardzo powolne, gdy robisz to dla setek elementów sekwencyjnie i czuję, że można to zrobić lepiej.

Aby to zadziałało, musiałem utrzymać dwie części kodu - jedną, która obliczy wysokość komórek, i taką, która faktycznie narysuje komórki, gdy nadejdzie czas.

Jeśli coś zmieniło się w modelu, musiałem zaktualizować oba te fragmenty kodu, i od czasu do czasu wciąż nawet nie pasują idealnie, czasami powodując, że komórki tabeli są nieco zbyt małe dla danego przedmiot lub zbyt duży.

My Proponowane rozwiązanie:

Więc chcę pozbyć się precalculating wysokość komórek. A), ponieważ łamie paradygmat MVC i B), ponieważ jest powolny.

Moja komórka rysuje się, w wyniku czego uzyskuje prawidłową wysokość komórki. Mój problem polega na tym, że nie mam możliwości powiedzieć tabeli, jaka jest wysokość komórki przed jej narysowaniem - do tego czasu jest już za późno.

Próbowałem wywoływać -cellForRowAtIndexPath: z poziomu -tableView:heightForRowAtIndexPath:, ale utknie w nieskończonej pętli, ponieważ pierwszy wywołuje sekundę w pewnym momencie, i na odwrót (przynajmniej to, co widziałem, gdy próbowałem go).

Ta opcja nie wchodzi w grę.

Jeśli nie określiłem rozmiaru na wysokości dla metody delegata wiersza, to widok tabeli przechodzi na rubwy. Komórki mają idealną wysokość, ale ich x jest pozycją komórek o stałych wysokościach.

Messed Table Cells http://jamsoftonline.com/images/messed_table_cells.png

Wskazówki jak dolna komórka jest prawidłowy rozmiar - to tylko nakładających poprzednią komórkę, a poprzedni komórka pokrywa jej poprzednią, i tak dalej i tak dalej.

Stosując tę ​​metodę podczas przewijania pojawia się kilka artefaktów, które mogą być związane z identyfikatorem ponownego użycia dla komórek.

Więc jakakolwiek pomoc tutaj byłaby wdzięcznie doceniona.

+0

mam ten sam problem. -cellForRowAtIndexPath: wywołania -tableView: heightForRowAtIndexPath: jeśli wywoływana w tym drugim (zauważ, że nie wywołuje tego ostatniego, jeśli nie jest wywoływana w drugim), doprowadzam mnie do szału. – an0

Odpowiedz

38

Oto, czego używam. NSString ma metodę, która wskaże wymiary pola tekstowego na podstawie informacji o czcionce i ograniczeń wysokości/szerokości, które mu dajesz.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSString *text = [self getTextForIndexPath:indexPath]; 
    UIFont *font = [UIFont systemFontOfSize:14]; 
    CGSize size = [self getSizeOfText:text withFont:font]; 

    return (size.height + 11); // I put some padding on it. 
} 

Potem piszesz sposób wyciągnąć tekst do tej celi ...

- (NSString *)getTextForIndexPath:(NSIndexPath *)indexPath 
{ 
    NSString *sectionHeader = [self.tableSections objectAtIndex:[indexPath section]]; 
    NSString *sectionContent = [self.tableData objectForKey:sectionHeader]; 

    return sectionContent; 
} 

A to, aby uzyskać rozmiar tekstu.

- (CGSize)getSizeOfText:(NSString *)text withFont:(UIFont *)font 
{ 
    return [text sizeWithFont:font constrainedToSize:CGSizeMake(280, 500)]; 
} 
+0

Kto to pogardził i dlaczego? – Jasarien

+1

Jak mogę użyć tej metody tylko dla jednej komórki w zgrupowanej tabeli Widok? Chciałbym zwrócić wysokość komórki na podstawie wysokości textView wewnątrz komórki ... – matteodv

+0

Witam. Chcę wiedzieć, co to jest 'self.tableSections' i' self.tableData'. Wiem, że są to NSArray i NSDictionary, ale czy oznacza to, że utworzyłeś tablicę sekcji tabel i słownik dla zawartości tych sekcji? Pytam, ponieważ korzystam tylko z jednej sekcji i nie mogę sprawić, żeby działała. –

2

Tylko myśl:

  • Co jeśli miał, powiedzmy, sześć różnych typów komórek, każda z własnym identyfikatorem i stałej wysokości. Jeden byłby dla komórki jednoliniowej, drugi dla komórki dwuliniowej, itd ...

  • Za każdym razem, gdy model się zmienia, oblicz wysokość dla tego wiersza, a następnie znajdź najbliższy typ komórki, który ma wysokość najbliżej do tego, czego potrzebujesz. Zapisz ten identyfikator typu celltype razem z modelem. Możesz także zapisać stałą wysokość wiersza dla tej komórki w modelu, aby można było ją zwrócić w wywołaniu tableview: heightForRowAtIndexPath (nie wziąłbym się zbytnio na to, żeby go obliczyć wewnątrz samej klasy komórki - technicznie nie jest to część funkcji rysowania komórki i czegoś więcej, czego używa tabela do decydowania, który typ komórki utworzyć).

  • W środowisku uruchomieniowym, gdy pojawi się monit o zwrócenie komórki dla tego wiersza, wszystko co musisz zrobić, to utworzyć (lub uzyskać z pamięci podręcznej komórki) komórkę z identyfikatorem typu komórki, wczytać wartości i dobrze jest jechać.

Jeżeli obliczenie wysokości komórka jest zbyt powolny, a następnie można ciągnąć ten sam trik cache tableview robi i to zrobić tylko na żądanie, gdy komórka wchodzi w widoku. W danym momencie wystarczy zrobić to tylko dla widocznych komórek, a następnie tylko dla pojedynczej komórki, która przewija się do widoku po obu stronach.

+0

Wcześniej bawiłem się tym pomysłem i nie mogłem zrobić tego, co chciałem. Ale może mogę spróbować jeszcze raz. – Jasarien

+0

Dobry i zabawny sposób, aby to zrobić źle –

0

Zdaję sobie sprawę, to nie będzie pracować dla Ciebie ze względu na nieskończoną pętlę można wymienić, ale miałem pewne sukcesy z wywołaniem metody Komórki layoutSubViews

Choć może to być trochę nieefektywne ze względu na wiele wywołań zarówno do komórkiForRowAtIndexPath, jak i layoutSubViews, uważam, że kod jest czystszy.

-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    MyCell *cell = (MyCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath]; 

    [cell layoutSubviews]; 

    return CGRectGetHeight(cell.frame); 
} 

I w kodzie układ:

- (void)layoutSubviews 
{ 
    [super layoutSubviews]; 

    //First expand the label to a large height to so sizeToFit isn't constrained 
    [self.myArbitrarilyLengthLabel setFrame:CGRectMake(self.myArbitrarilyLengthLabel.frame.origin.x, 
              self.myArbitrarilyLengthLabel.frame.origin.y, 
              self.myArbitrarilyLengthLabel.frame.size.width, 
              1000)]; 


    //let sizeToFit do its magic 
    [self.myArbitrarilyLengthLabel sizeToFit]; 

    //resize the cell to encompass the newly expanded label 
    [self setFrame:CGRectMake(self.frame.origin.x, 
          self.frame.origin.y, 
          self.frame.size.width, 
           CGRectGetMaxY(self.myArbitrarilyLengthLabel.frame) + 10)]; 
} 
Powiązane problemy