W storyboardzie, jak zrobić niestandardową komórkę do użytku z wieloma kontrolerami?

Próbuję użyć storyboardów w aplikacji, nad którą pracuję. W aplikacji znajdują się Listy i Użytkownicy i każdy zawiera kolekcję innych (członków listy, listy należące do użytkownika). W związku z tym mam ListCell i UserCell klasy. Celem jest, aby były one ponownie używane w całej aplikacji (tj. w dowolnym kontrolerze tableview).

I tu mam problem.

Jak utworzyć niestandardową komórkę tableview w storyboard, który może być ponownie używany w dowolnym kontrolerze widoku?

Oto konkretne rzeczy, które próbowałem do tej pory.

  • W kontrolerze # 1 Dodano prototypową komórkę, ustawiono klasę na moją UITableViewCell podklasę, ustawiono identyfikator ponownego użycia, dodano etykiety i podłączono je do gniazd klasy. W kontrolerze # 2 dodano pustą komórkę prototypu, ustaw ją na tę samą klasę i użyj ponownie id jak poprzednio. Po uruchomieniu etykiety nigdy nie pojawiają się, gdy komórki są wyświetlane w kontrolerze #2. Działa dobrze w sterowniku #1.

  • Zaprojektowano każdy typ ogniwa w innej stalówce i podłączono do odpowiedniej klasy ogniw. W storyboard dodano pustą prototypową komórkę i ustaw jej klasę i identyfikator ponownego użycia, aby odnosił się do mojej klasy komórki. W metodach controllerów viewDidLoad Zapisano te pliki NIB dla identyfikatora ponownego użycia. Gdy pokazano, komórki w obu kontrolerach były puste jak prototyp.

  • Przechowywane prototypy w obu kontrolerach puste i ustawić klasę i ponownie użyć id do mojej klasy komórki. Konstruowanie interfejsu komórek całkowicie w kodzie. Komórki działają doskonale we wszystkich kontrolerach.

W drugim przypadku podejrzewam, że prototyp zawsze nadpisuje stalówkę i jeśli zabiję komórki prototypowe, zarejestrowanie mojej stalówki dla identyfikatora ponownego użycia zadziała. Ale wtedy nie byłbym w stanie skonfigurować segmentów z komórek do innych ramek, co jest naprawdę celem korzystania ze storyboardów.

Na koniec dnia chcę dwóch rzeczy: podłączyć przepływy oparte na tableview w storyboardzie i zdefiniować układy komórek wizualnie, a nie w kodzie. Jak dotąd Nie wiem, jak je zdobyć.

Author: Dharmesh Dhorajiya, 2012-02-12

6 answers

Jak rozumiem, chcesz:

  1. Zaprojektuj komórkę w IB, która może być używana w wielu scenach scenorysów.
  2. Konfiguracja unikalnych scenorysów z tej komórki, w zależności od sceny, w której znajduje się komórka.

Niestety, obecnie nie ma sposobu, aby to zrobić. Aby zrozumieć, dlaczego poprzednie próby nie powiodły się, musisz dowiedzieć się więcej o tym, jak działają storyboardy i prototypowe komórki widoku tabeli. (Jeśli nie dbasz o dlaczego te inne próby nie powiodły się, możecie już iść. Nie mam dla Ciebie żadnych magicznych obejść, poza sugerowaniem, że zgłaszasz błąd.)

[11]}storyboard to w istocie niewiele więcej niż zbiór .pliki xib. Kiedy ładujesz kontroler widoku tabeli, który ma kilka prototypowych komórek z storyboardu, oto, co się dzieje:]}
  • każda komórka prototypowa jest właściwie własną mini-stalówką. Gdy kontroler widoku tabeli ładuje się, przechodzi przez każdy z prototypów komórki i wywołania -[UITableView registerNib:forCellReuseIdentifier:].
  • widok tabeli pyta kontroler o komórki.
  • prawdopodobnie zadzwonisz -[UITableView dequeueReusableCellWithIdentifier:]
  • Gdy żądasz komórki o podanym identyfikatorze ponownego użycia, sprawdza ona, czy ma zarejestrowaną stalówkę. Jeśli tak, tworzy instancję tej komórki. Składa się z następujących kroków:

    1. spójrz na klasę komórki, zdefiniowaną w stalówce komórki. Call [[CellClass alloc] initWithCoder:].
    2. Metoda -initWithCoder: przechodzi przez i dodaje podviews i ustawia właściwości zdefiniowane w stalówce. (IBOutletS prawdopodobnie też się tu podłączyć, choć tego nie testowałem; może się to zdarzyć w -awakeFromNib)
  • Konfigurujesz komórkę tak, jak chcesz.

Ważną rzeczą, którą należy tutaj zauważyć jest rozróżnienie między klasą komórki i wyglądem wizualnym komórki. Można utworzyć dwie oddzielne komórki prototypowe tej samej klasy, ale z ich podwidywaniami zupełnie inaczej. W rzeczywistości, jeśli używasz domyślnych stylów UITableViewCell, to właśnie to się dzieje. Na przykład styl" Default "i styl" Subtitle " są reprezentowane przez tę samą klasę UITableViewCell.

Jest to ważne: Klasa komórki nie ma korelacji jeden do jednego z określoną hierarchią widoku . Hierarchia widoku jest całkowicie określona przez to, co znajduje się w komórce prototypu, która została zarejestrowana w tym konkretnym kontroler.

Należy również zauważyć, że identyfikator ponownego użycia komórki nie został zarejestrowany w jakimś globalnym ambulatorium komórkowym. Identyfikator ponownego użycia jest używany tylko w kontekście pojedynczej instancji UITableView.


Biorąc pod uwagę te informacje, spójrzmy na to, co wydarzyło się w Twoich powyższych próbach.

W kontrolerze # 1 dodałem prototyp komórki, ustawiłem klasę na mój Podklasa UITableViewCell, ustawia identyfikator ponownego użycia, dodaje etykiety i przewodowe do punktów sprzedaży. W Kontroler # 2, dodano pusty komórka prototypowa, ustaw ją na tę samą klasę i użyj ponownie id jak wcześniej. Kiedy działa, etykiety nigdy nie pojawiają się, gdy komórki są wyświetlane w Kontroler # 2. Działa dobrze w kontrolerze # 1.

Tego się oczekuje. Podczas gdy obie komórki miały tę samą klasę, hierarchia widoków przekazywana do komórki w kontrolerze # 2 była całkowicie pozbawiona podglądów. Więc masz pustą komórkę, która jest dokładnie tym, co umieściłeś w prototypie.

Zaprojektowano każdą komórkę wpisz inną stalówkę i podłącz do odpowiednia klasa komórek. W storyboard dodano pustą komórkę prototypu i ustaw jego klasę i ponownie użyj id, aby odnosić się do mojej klasy komórki. W metody viewDidLoad kontrolerów, zarejestrowały te pliki NIB dla ponowne użycie identyfikatora. Gdy pokazano, komórki w obu kontrolerach były puste jak prototyp.

Ponownie, tego się oczekuje. Identyfikator ponownego użycia nie jest współdzielony między scenami scenorysów lub stalówkami, więc fakt, że wszystkie te odrębne komórki miały ten sam IDENTYFIKATOR ponownego użycia był bez znaczenia. Komórka, którą otrzymasz z widoku tableview, będzie miała wygląd, który pasuje do prototypowej komórki w tej scenie storyboardu.

To rozwiązanie było jednak bliskie. Jak zauważyłeś, możesz po prostu programowo zadzwonić -[UITableView registerNib:forCellReuseIdentifier:], mijając UINib zawierającą komórkę, i odzyskasz tę samą komórkę. (To nie dlatego, że prototyp "nadpisywał" stalówkę; po prostu nie zarejestrowałeś stalówki w widoku tableview, więc nadal patrzył na stalówka osadzona w storyboardzie.) Niestety, w tym podejściu jest wada - nie ma możliwości podłączenia storyboardu do komórki w samodzielnej stalówce.

Utrzymywała prototypy w obu kontrolerach pustą i ustawioną klasę i ponowne użycie id na zajęcia z komórki. Zbudowany interfejs komórek w całości w kodzie. Komórki działa doskonale we wszystkich kontrolerach.

Naturalnie. Mam nadzieję, że nie jest to zaskakujące.


Dlatego nie zadziałało. Możesz zaprojektować swój komórki w samodzielnych stalówkach i używaj ich w wielu scenach scenorysowych; po prostu nie możesz obecnie podłączyć segmentów scenorysów do tych komórek. Mam nadzieję, że nauczyłeś się czegoś podczas czytania tego.

 202
Author: BJ Homer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-13 01:18:53

Pomimo wspaniałej odpowiedzi BJ Homera, czuję, że mam rozwiązanie. Jeśli chodzi o moje testy, to działa.

Concept: Tworzenie niestandardowej klasy dla komórki xib. Tam można poczekać na zdarzenie dotykowe i wykonać segue programowo. Teraz potrzebujemy tylko odniesienia do kontrolera wykonującego Segue. Moim rozwiązaniem jest ustawienie go w tableView:cellForRowAtIndexPath:.

Przykład

Mam DetailedTaskCell.xib zawierający komórkę tabeli, której chciałbym użyć w wielu tabelach wyświetleń:

DetailedTaskCell.xib

Istnieje klasa niestandardowa TaskGuessTableCell dla tej komórki:

Tutaj wpisz opis obrazka

Tutaj dzieje się magia.
// TaskGuessTableCell.h
#import <Foundation/Foundation.h>

@interface TaskGuessTableCell : UITableViewCell
@property (nonatomic, weak) UIViewController *controller;
@end

// TashGuessTableCell.m
#import "TaskGuessTableCell.h"

@implementation TaskGuessTableCell

@synthesize controller;

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSIndexPath *path = [controller.tableView indexPathForCell:self];
    [controller.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
    [controller performSegueWithIdentifier:@"FinishedTask" sender:controller];
    [super touchesEnded:touches withEvent:event];
}

@end

Mam wiele segmentów, ale wszystkie mają tę samą nazwę: "FinishedTask". Jeśli chcesz być elastyczny tutaj, proponuję dodać inną nieruchomość.

ViewController wygląda tak:

// LogbookViewController.m
#import "LogbookViewController.h"
#import "TaskGuessTableCell.h"

@implementation LogbookViewController

- (void)viewDidLoad
{
    [super viewDidLoad]

    // register custom nib
    [self.tableView registerNib:[UINib nibWithNibName:@"DetailedTaskCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"DetailedTaskCell"];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TaskGuessTableCell *cell;

    cell = [tableView dequeueReusableCellWithIdentifier:@"DetailedTaskCell"];
    cell.controller = self; // <-- the line that matters
    // if you added the seque property to the cell class, set that one here
    // cell.segue = @"TheSegueYouNeedToTrigger";
    cell.taskTitle.text  = [entry title];
    // set other outlet values etc. ...

    return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([[segue identifier] isEqualToString:@"FinishedTask"])
    {
        // do what you have to do, as usual
    }

}

@end

Mogą być bardziej eleganckie sposoby, aby osiągnąć to samo, ale-to działa! :)

 58
Author: ericteubert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-04 08:50:38

Szukałem tego i znalazłem ODPOWIEDŹ Richarda Venable. Dla mnie działa.

IOS 5 zawiera nową metodę na UITableView: registerNib: forCellReuseIdentifier:

Aby go użyć, Umieść UITableViewCell w stalówce. To musi być jedyny korzeń obiekt w stalówce.

Możesz zarejestrować stalówkę po załadowaniu widoku tableView, a następnie po wywołanie dequeueReusableCellWithIdentifier: z identyfikatorem komórki, To wyciągnie go ze stalówki, tylko jakbyś użył storyboardu komórka prototypowa.

 15
Author: Odrakir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:30

BJ Homer dał doskonałe wyjaśnienie tego, co się dzieje.

Z praktycznego punktu widzenia dodałbym, że biorąc pod uwagę, że nie możesz mieć komórek jako xibs i połączyć segue, najlepszym wyborem jest posiadanie komórki jako xib - przejścia są o wiele łatwiejsze w utrzymaniu niż układy komórek i właściwości w wielu miejscach, a twoje segmenty prawdopodobnie będą się różnić od różnych kontrolerów i tak. Możesz zdefiniować segue bezpośrednio z kontrolera widoku tabeli do następnego kontrolera i wykonaj go w kodzie. .

Kolejna uwaga jest taka, że posiadanie komórki jako osobnego pliku xib uniemożliwia podłączenie żadnych akcji itp. bezpośrednio do kontrolera widoku tabeli (i tak tego nie rozgryzłem - nie można zdefiniować właściciela pliku jako nic znaczącego). Pracuję nad tym, definiując protokół, do którego oczekuje się, że kontroler widoku tabeli komórki będzie zgodny i dodając kontroler jako słabą właściwość, podobną do delegata, w / align = "left" /

 10
Author: jrturton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-12 07:36:23

Swift 3

BJ Homer dał doskonałe wyjaśnienie, pomaga mi zrozumieć pojęcie. Do make a custom cell reusable in storyboard, który może być użyty w dowolnym TableViewController musimy podejść mix the Storyboard and xib. Załóżmy, że mamy komórkę o nazwie CustomCell, która ma być użyta w TableViewControllerOne i TableViewControllerTwo. Robię to krokami.
1. File > New > Click File > Select Cocoa Touch Class > click Next > Give Name of your class ( for example CustomCell)> select Subclass as UITableVieCell > Tick the also create XIB pole wyboru plik i naciśnij Dalej.
2. Dostosuj komórkę, jak chcesz i ustaw identyfikator w Inspektorze atrybutów dla komórki, tutaj ustawimy jako CellIdentifier. Ten identyfikator będzie używany w Twoim kontrolerze ViewController do identyfikacji i ponownego użycia komórki.
3. teraz musimy tylko register this cell w naszym ViewController viewDidLoad. Nie potrzeba żadnej metody inicjalizacji.
4. teraz możemy użyć tej niestandardowej komórki w dowolnym widoku tabeli.

In TableViewControllerOne

let reuseIdentifier = "CellIdentifier"

override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: reuseIdentifier)
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier:reuseIdentifier, for: indexPath) as! CustomCell
    return cell!
}
 10
Author: Kunal Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-16 05:18:40

Znalazłem sposób, aby załadować komórkę do tego samego VC, nie testowane dla segues. Może to być obejście dla utworzenia komórki w oddzielnej stalówce

Załóżmy, że masz jedną tabelę VC i 2 i chcesz zaprojektować komórkę w storyboardzie i użyć jej w obu tabelach.

(np: tabela i pole wyszukiwania z kontrolerem UISearchController z tabelą wyników i chcesz użyć tej samej komórki w obu)

Gdy kontroler zapyta o komórkę zrób to:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * identifier = @"CELL_ID";

    ContactsCell *cell = [self.YOURTABLEVIEW dequeueReusableCellWithIdentifier:identifier];
  // Ignore the "tableView" argument
}

I tutaj masz swoją komórkę ze storyboardu

 5
Author: João Nunes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-18 14:57:05