Obecnie tworzę aplikację, która będzie miała wiele timerów, które w zasadzie są takie same.
Chcę utworzyć niestandardową klasę, która używa całego kodu timerów, a także układu / animacji, więc mogę mieć 5 identycznych timerów, które działają niezależnie od siebie.
Układ utworzyłem za pomocą IB (xcode 4.2), a cały kod timerów jest obecnie tylko w klasie viewcontroller.
Mam trudność w zrozumieniu tego, jak zawrzeć wszystko w niestandardowej klasie, a następnie dodać to do kontrolera widoku, każda pomoc byłaby bardzo mile widziana.
UITableViewCell
lubUICollectionViewCell
. W moim przypadku potrzebuję małego, ale dość złożonego widoku, którego mogę używać wielokrotnie w kontrolerach i widokach kolekcji. Projektanci ciągle go przerabiają, więc chcę, aby układ był zdefiniowany w jednym miejscu. Stąd stalówka.Odpowiedzi:
Cóż, odpowiadając koncepcyjnie, twój licznik czasu powinien być prawdopodobnie podklasą
UIView
zamiastNSObject
.Aby utworzyć instancję timera w IB, po prostu przeciągnij i
UIView
upuść ją w widoku kontrolera widoku i ustaw jej klasę na nazwę klasy timera.Pamiętaj by
#import
klasie licznika czasu w kontrolerze widoku.Edycja: dla projektu IB (dla tworzenia instancji kodu zobacz historię wersji)
W ogóle nie jestem zaznajomiony ze scenorysami, ale wiem, że możesz skonstruować swój interfejs w IB, używając
.xib
pliku, który jest prawie identyczny z używaniem wersji storyboardowej; Powinieneś nawet być w stanie skopiować i wkleić swoje widoki jako całość z istniejącego interfejsu do.xib
pliku.Aby to przetestować, utworzyłem nowy pusty o
.xib
nazwie „MyCustomTimerView.xib”. Następnie dodałem widok, a do tego dodałem etykietę i dwa przyciski. Tak jak tak:Stworzyłem nową podklasę klasy celu C o
UIView
nazwie „MyCustomTimer”. W moim.xib
ustawiłem klasę właściciela mojego pliku na MyCustomTimer . Teraz mogę łączyć akcje i gniazda, tak jak każdy inny widok / kontroler. Wynikowy.h
plik wygląda następująco:Jedyną przeszkodą, jaka mi pozostała, jest uzyskanie tego
.xib
w mojejUIView
podklasie. Używanie a.xib
radykalnie zmniejsza wymaganą konfigurację. A ponieważ używasz scenorysów do ładowania timerów, o których wiemy, że-(id)initWithCoder:
jest to jedyny inicjator, który zostanie wywołany. Oto jak wygląda plik implementacji:Metoda o nazwie
loadNibNamed:owner:options:
robi dokładnie to, na co wygląda. Ładuje końcówkę i ustawia właściwość „Właściciel pliku” na siebie. Wyodrębniamy pierwszy obiekt w tablicy i jest to widok główny stalówki. Dodajemy widok jako podwidok i Voila jest na ekranie.Oczywiście zmienia to tylko kolor tła etykiety, gdy naciskane są przyciski, ale ten przykład powinien pomóc Ci dobrze działać.
Uwagi na podstawie komentarzy:
Warto zauważyć, że jeśli masz problemy z nieskończoną rekurencją, prawdopodobnie przegapiłeś subtelną sztuczkę tego rozwiązania. Nie robi tego, co myślisz, że robi. Widok umieszczony w serii ujęć nie jest widoczny, ale zamiast tego ładuje inny widok jako widok podrzędny. Widok, który ładuje, jest widokiem zdefiniowanym w końcówce. „Właścicielem pliku” w końcówce jest ten niewidoczny widok. Fajne jest to, że ten niewidoczny widok jest nadal klasą Objective-C, która może być używana jako swego rodzaju kontroler widoku dla widoku, który przynosi ze stalówki. Na przykład
IBAction
metody wMyCustomTimer
klasie są czymś, czego można oczekiwać bardziej w kontrolerze widoku niż w widoku.Na marginesie, niektórzy mogą twierdzić, że to się psuje
MVC
i częściowo się z tym zgadzam. Z mojego punktu widzenia jest to bardziej związane z niestandardowymUITableViewCell
, który czasami musi być częściowo kontrolerem.Warto też zauważyć, że ta odpowiedź miała dostarczyć bardzo konkretnego rozwiązania; utwórz jedną końcówkę, której wystąpienie można utworzyć wiele razy w tym samym widoku, co w scenorysie. Na przykład, możesz łatwo wyobrazić sobie sześć z tych timerów jednocześnie na ekranie iPada. Jeśli potrzebujesz tylko określić widok dla kontrolera widoku, który ma być używany wiele razy w Twojej aplikacji, to rozwiązanie dostarczone przez jyavenard na to pytanie jest prawie na pewno lepszym rozwiązaniem dla Ciebie.
źródło
userInfo
właściwości w powiadomieniu@property(nonatomic,copy) NSDictionary *userInfo;
File's Owner
jest ustawiona na nazwę twojej klasy, rozwiązało mój problem z nieskończoną rekurencją.[self addSubview:[[[NSBundle mainBundle] loadNibNamed:@"MyCustomTimerView" owner:self options:nil] objectAtIndex:0]];
Dodanie drugiego UIView ... To trochę wygląda dziwnie dla mnie, nikt inny nie czuje tego samego? Jeśli tak, to czy jest to coś stworzonego przez Apple? Czy może ktoś znalazł rozwiązanie, robiąc to?Szybki przykład
Zaktualizowano dla Xcode 10 i Swift 4
Oto podstawowy przewodnik. Pierwotnie wiele się tego nauczyłem, oglądając serię filmów na Youtube . Później zaktualizowałem moją odpowiedź na podstawie tego artykułu .
Dodaj pliki widoku niestandardowego
Poniższe dwa pliki utworzą widok niestandardowy:
UIView
podklasaSzczegóły dotyczące ich dodawania znajdują się poniżej.
Plik Xib
Dodaj plik .xib do projektu (Plik> Nowy> Plik ...> Interfejs użytkownika> Widok) . Dzwonię do siebie
ReusableCustomView.xib
.Utwórz układ, który ma mieć niestandardowy widok. Jako przykład zrobię układ z a
UILabel
i aUIButton
. Dobrym pomysłem jest użycie automatycznego układu, aby rzeczy zmieniały się automatycznie, niezależnie od tego, jaki rozmiar ustawisz później. (Użyłem Freeform dla rozmiaru xib w Inspektorze atrybutów, aby móc dostosować symulowane metryki, ale nie jest to konieczne.)Szybki plik
Dodaj plik .swift do projektu (Plik> Nowy> Plik ...> Źródło> Swift Plik) . To jest podklasa
UIView
i nazywam swojąReusableCustomView.swift
.Ustaw plik Swift jako właściciela
Wróć do pliku .xib i kliknij opcję „Właściciel pliku” w konspekcie dokumentu. W Inspektorze tożsamości wpisz nazwę swojego pliku .swift jako nazwę klasy niestandardowej.
Dodaj kod widoku niestandardowego
Zastąp
ReusableCustomView.swift
zawartość pliku następującym kodem:Upewnij się, że pisownia nazwy Twojego pliku .xib jest poprawna.
Podłącz gniazda i akcje
Podłącz gniazda i akcje, przeciągając kontrolki z etykiety i przycisku w układzie XIB do szybkiego kodu widoku niestandardowego.
Użyj własnego widoku
Twój widok niestandardowy jest teraz zakończony. Wszystko, co musisz zrobić, to dodać
UIView
dowolne miejsce w swojej głównej planszy. Ustaw nazwę klasy widoku naReusableCustomView
w Inspektorze tożsamości.źródło
Bundle.main
naBundle(for: ...)
załatwia sprawę. NajwyraźniejBundle.main
jest niedostępny w czasie projektowania.init(frame:)
. Po dodaniu tego (i wciągnięciu całego kodu inicjalizacyjnego do jakiejścommonInit()
funkcji) działa dobrze i wyświetla się w IB. Zobacz więcej informacji tutaj: stackoverflow.com/questions/31265906/…Odpowiedź dla kontrolerów widoku, a nie widoków :
Jest łatwiejszy sposób na załadowanie xib z storyboardu. Powiedzmy, że twój kontroler jest typu MyClassController, który dziedziczy po
UIViewController
.Dodajesz
UIViewController
używając IB w swoim storyboardzie; zmień typ klasy na MyClassController. Usuń widok, który został automatycznie dodany do serii ujęć.Upewnij się, że XIB, który chcesz wywołać, nazywa się MyClassController.xib.
Gdy klasa zostanie utworzona podczas ładowania scenorysu, xib zostanie automatycznie załadowany. Przyczyną tego jest domyślna implementacja,
UIViewController
która wywołuje XIB o nazwie z nazwą klasy.źródło
'Could not load NIB in bundle: 'NSBundle </Users/me/.../MyAppName.app> (loaded)' with name 'uB0-aR-WjG-view-4OA-9v-tyV''
. Zwróć uwagę na whacko nibName. Używam poprawnej nazwy klasy dla stalówki w końcówce.To nie jest tak naprawdę odpowiedź, ale myślę, że warto podzielić się tym podejściem.
Cel C
Szybki
Opcjonalny :
To wszystko, teraz możesz dodać swój niestandardowy widok do swojego storyboardu i zostanie on pokazany :)
CustomViewWithXib.h :
CustomViewWithXib.m :
CustomViewWithXib.swift :
Można znaleźć kilka przykładów tutaj .
Mam nadzieję, że to pomoże.
źródło