Próbuję zrobić coś nieco skomplikowanego, ale coś, co powinno być możliwe. Oto wyzwanie dla was wszystkich ekspertów (to forum jest gromadką was wszystkich :)).
Tworzę „komponent” Kwestionariusza, który chcę załadować na NavigationContoller
(mój QuestionManagerViewController
). „Składnik” jest „pusty” UIViewController
, który może ładować różne widoki w zależności od pytania, na które należy odpowiedzieć.
Tak to robię:
- Utwórz obiekt Question1View jako
UIView
podklasę, definiując niektóreIBOutlets
. - Utwórz (za pomocą Konstruktora interfejsów)
Question1View.xib
(TUTAJ JEST GDZIE MOŻLIWY JEST MOJA PROBLEM ). Ustawiłem zarówno te, jakUIViewController
iUIView
klasy klasy Question1View. - Łączę wyloty z komponentem widoku (używając IB).
Zastępuję
initWithNib
moje,QuestionManagerViewController
aby wyglądać tak:- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) { // Custom initialization } return self; }
Po uruchomieniu kodu pojawia się następujący błąd:
2009-05-14 15: 05: 37.152 iMobiDines [17148: 20b] *** Kończenie aplikacji z powodu nieprzechwyconego wyjątku
NSInternalInconsistencyException
”, powód:„-[UIViewController _loadViewFromNibNamed:bundle:]
załadowałem końcówkę „Question1View”, ale ujście widoku nie zostało ustawione ”.
Jestem pewien, że istnieje sposób na załadowanie widoku przy użyciu pliku stalówki, bez potrzeby tworzenia klasy viewController.
źródło
Dziękuję wam wszystkim. Znalazłem sposób na robienie tego, co chciałem.
UIView
zeIBOutlet
s potrzebne.UIViewController
(bez niestandardowej podklasy, ale „prawdziwa”). Widok właściciela pliku jest połączony z widokiem głównym, a jego klasa jest zadeklarowana jako ta z kroku 1).IBOutlet
s.DynamicViewController
Można uruchomić swoją logikę do decydowania co zobaczyć / XIb do obciążenia. Po podjęciu decyzji wloadView
metodzie umieść coś takiego:Otóż to!
Metoda głównego pakietu
loadNibNamed
zajmie się inicjowaniem widoku i tworzeniem połączeń.Teraz ViewController może wyświetlać widok lub inny w zależności od danych w pamięci, a ekran „macierzysty” nie musi niepokoić się tą logiką.
źródło
Nie jestem pewien, o czym mówią niektóre odpowiedzi, ale muszę tu podać tę odpowiedź, kiedy następnym razem będę wyszukiwać w Google. Słowa kluczowe: „Jak załadować UIView z końcówki” lub „Jak załadować UIView z NSBundle”.
Oto kod prawie 100% od książki Apress Beginning od iPhone'a 3 (strona 247, „Korzystanie z nowej komórki widoku tabeli”):
Zakłada się, że masz
UIView
podklasę o nazwieBlah
stalówka,Blah
która zawieraUIView
klasę ustawioną naBlah
.Kategoria: NSObject + LoadFromNib
Szybkie rozszerzenie
I przykład w użyciu:
źródło
isKindOf
jesteś chroniony przed zmianami struktury pakietu.assert
Będzie prawdopodobnie lepszym rozwiązaniem. W ten sposób ukryjesz tylko problem.for
pętli. Uzupełnia to.Dla wszystkich, którzy muszą zarządzać więcej niż jedną instancją widoku niestandardowego, tj. Kolekcją Outlet , połączyłem i dostosowałem odpowiedzi @Gonso, @AVeryDev i @Olie w ten sposób:
Utwórz niestandardowy
MyView : UIView
i ustaw go jako „ klasę niestandardową ” katalogu głównegoUIView
w żądanym XIB ;Utwórz wszystkie gniazda, w których potrzebujesz
MyView
(zrób to teraz, ponieważ po punkcie 3 IB zaproponuje ci podłączenie gniazd do,UIViewController
a nie do niestandardowego widoku, jak chcemy);Ustaw
UIViewController
jako „ właściciela pliku ” widoku niestandardowego XIB ;W
UIViewController
dodawać noweUIViews
dla każdej instancjiMyView
chcesz, i podłączyć je doUIViewController
stworzenia kolekcji Outlet : te poglądy będą działać jako widoki „Okładki” Widok niestandardowy przypadkach;Wreszcie, w
viewDidLoad
swojejUIViewController
dodać następujące wiersze:źródło
Użyłbym UINib do utworzenia niestandardowego UIView do ponownego użycia
Pliki potrzebne w tym przypadku to MyCustomView.xib , MyCustomViewClass.h oraz MyCustomViewClass.m Uwaga, która
[UINib instantiateWithOwner]
zwraca tablicę, dlatego należy użyć elementu odzwierciedlającego UIView, którego chcesz ponownie użyć. W tym przypadku jest to pierwszy element.źródło
Nie powinieneś ustawiać klasy kontrolera widoku jako podklasy
UIView
w Konstruktorze interfejsów. To z pewnością przynajmniej część twojego problemu. Pozostaw to jakoUIViewController
część podklasy lub inną niestandardową klasę.Co do ładowania tylko widok z XIb, byłem przy założeniu, że musiał mieć jakiś kontroler widoku (nawet jeśli nie rozciągają
UIViewController
, co może być zbyt dużej gramaturze do swoich potrzeb) ustawiony jako plik Właścicielem interfejs Konstruktor, jeśli chcesz go użyć do zdefiniowania interfejsu. Zrobiłem też trochę badań, aby to potwierdzić. Wynika to z faktu, że w przeciwnym razie nie byłoby sposobu na uzyskanie dostępu do żadnego z elementów interfejsuUIView
ani nie byłoby sposobu na wywołanie własnych metod w kodzie przez zdarzenia.Jeśli używasz
UIViewController
jako właściciela pliku dla swoich widoków, możesz po prostu użyć,initWithNibName:bundle:
aby go załadować i odzyskać obiekt kontrolera widoku. W IB upewnij się, że ustawiłeśview
ujście na widok z interfejsem w Xib. Jeśli używasz innego typu obiektu jako plik Właścicielem, trzeba użyćNSBundle
„sloadNibNamed:owner:options:
metody, aby załadować stalówkę, przekazując instancję pliku Właścicielem metody. Wszystkie jego właściwości zostaną ustawione poprawnie zgodnie z punktami sprzedaży zdefiniowanymi w IB.źródło
Możesz także użyć parametru initWithNibName UIViewController zamiast loadNibNamed. Uważam, że jest to prostsze.
Teraz wystarczy utworzyć MySubView.xib i MySubView.h / m. W MySubView.xib ustaw klasę właściciela pliku na UIViewController i wyświetl klasę na MySubView.
Możesz ustawić i rozmiar
subview
używanego nadrzędnego pliku xib.źródło
To świetne pytanie (+1), a odpowiedzi były prawie pomocne;) Przepraszam chłopaki, ale miałem dość czasu, prześlizgując się przez to, chociaż zarówno Gonso, jak i AVeryDev dali dobre wskazówki. Mam nadzieję, że ta odpowiedź pomoże innym.
MyVC
jest kontrolerem widoku przechowującym wszystkie te rzeczy.MySubview
jest widokiem, który chcemy załadować z XibMySubView
odpowiednim rozmiarze i kształcie oraz w odpowiednim miejscu.W MyVC.h, mieć
W MyVC.m
@synthesize mySubView;
i nie zapomnij go wypuścićdealloc
.UIView *view
(może być niepotrzebne, ale działało dla mnie.) Zsyntetyzuj i wypuść w .mMySubview
i połącz właściwość widoku ze swoim widokiem.IBOutlet
zgodnie z potrzebamiZ powrotem w MyVC.m, mieć
Problem polegał na tym, że podpowiedzi w innych odpowiedziach załadowały mój widok z Xib, ale NIE zastąpiły widoku w MyVC (duh!) - musiałem to zamienić sam.
Ponadto, aby uzyskać dostęp do
mySubview
metod,view
właściwość w pliku .xib musi być ustawiona naMySubview
. W przeciwnym razie powraca jako zwykły staryUIView
.Jeśli istnieje sposób na załadowanie
mySubview
bezpośrednio z własnego Xiba, to by się zachwiało, ale to doprowadziło mnie tam, gdzie powinienem być.źródło
To powinno być łatwiejsze. Skończyło się na rozszerzeniu
UIViewController
i dodaniuloadNib:inPlaceholder:
selektora. Teraz mogę powiedziećOto kod kategorii (robi to samo rigamarole, jak opisano przez Gonso):
źródło
W szybkim tempie
W rzeczywistości moim rozwiązaniem tego problemu było załadowanie widoku w viewDidLoad w moim CustonViewController, w którym chciałem użyć takiego widoku:
Nie ładuj widoku w
loadView()
metodzie! Metoda loadView służy do ładowania widoku niestandardowego kontrolera ViewController.źródło
Ja też chciałem zrobić coś podobnego, oto co znalazłem: (SDK 3.1.3)
Mam kontroler widoku A (sam będący własnością kontrolera Nav), który ładuje VC B po naciśnięciu przycisku:
W AViewController.m
Teraz VC B ma interfejs z Bnib, ale po naciśnięciu przycisku chcę przejść do „trybu edycji”, który ma oddzielny interfejs użytkownika z innej końcówki, ale nie chcę nowego VC dla trybu edycji, Chcę, aby nowa końcówka była skojarzona z moim istniejącym B VC.
Tak więc w BViewController.m (w metodzie naciskania przycisków)
Następnie na innym przycisku naciśnij (aby wyjść z trybu edycji):
i wróciłem do mojego oryginalnego Bniba.
Działa to dobrze, ale zauważ, że mój plik EditMode.nib ma tylko 1 obiekt najwyższego poziomu, obiekt UIView obj. Nie ma znaczenia, czy właściciel pliku w tej stalówce jest ustawiony jako BViewController, czy domyślny obiekt NSObject, ALE upewnij się, że widok ujścia właściciela pliku NIE jest ustawiony na cokolwiek. Jeśli tak, to mam awarię exc_bad_access i xcode kontynuuje ładowanie ramek stosu 6677 pokazujących wewnętrzną metodę UIView wielokrotnie wywoływaną ... więc wygląda jak nieskończona pętla. (The View Outlet JEST jednak ustawiony w moim oryginalnym Bnib)
Mam nadzieję że to pomoże.
źródło
Stworzyłem kategorię, którą lubię:
UIView+NibInitializer.h
UIView+NibInitializer.m
Następnie zadzwoń w następujący sposób:
Użyj nazwy stalówki, jeśli nazwa stalówki jest inna niż nazwa twojej klasy.
Aby zastąpić go w podklasach dla dodatkowego zachowania, może wyglądać następująco:
źródło
Dla użytkownika Swift z opcją do wyboru:
UIView
podklasę i pliki xib , które nazwiemy na podstawie własnej nazwy klasy: w naszym przypadku MemeView. W klasie Meme View pamiętaj, aby zdefiniować ją jako możliwą do@IBDesignable
przypisania za pomocą atrybutu przed deklaracją klasyPamiętaj, aby ustawić właściciela pliku w xib za pomocą naszej niestandardowej
UIView
podklasy w panelu Inspektora IndetityW pliku xib możemy teraz budować nasz interfejs, tworzyć ograniczenia, tworzyć gniazda, akcje itp.
Musimy zaimplementować kilka metod w naszej klasie niestandardowej, aby po zainicjowaniu otworzyć xib
class XibbedView: UIView {
}
W naszej klasie niestandardowej możemy również zdefiniować niektóre właściwości podlegające inspekcji, aby mieć nad nimi pełną kontrolę z poziomu konstruktora interfejsu
@IBDesignable class MemeView: XibbedView {
}
Kilka przykładów:
Jeśli musimy dodać więcej informacji, gdy widok jest wyświetlany w serii ujęć lub innym Xib, aby to zrobić, możemy to zaimplementować
prepareForInterfaceBuilder()
, ta metoda zostanie wykonana tylko podczas otwierania pliku w narzędziu do tworzenia interfejsów. Jeśli zrobiłeś wszystko, co napisałem, ale nic nie działa, jest to sposób na debugowanie głównego widoku poprzez dodanie punktów przerwania w jego implementacji. Oto hierarchia widoków.Mam nadzieję, że to pomoże w pobraniu pełnej próbki tutaj
źródło
let nib = loadNib(nibName)
to jest instancja XibbedView, jeśli wywołasz `` addSubview (nib) `` `, to dodajesz jedną instancję XibbedView do innej instancji XibbedView?Uważam, że ten wpis na blogu Aarona Hillegassa (autor, instruktor, ninja Cocoa) jest bardzo pouczający. Nawet jeśli nie zastosujesz jego zmodyfikowanego podejścia do ładowania plików NIB przez wyznaczony inicjator, prawdopodobnie przynajmniej lepiej zrozumiesz trwający proces. Ostatnio stosuję tę metodę, aby odnieść wielki sukces!
źródło
Poprzednia odpowiedź nie uwzględnia zmiany w strukturze NIB (XIB), która nastąpiła między wersją 2.0 a 2.1 zestawu SDK iPhone'a. Treść użytkownika zaczyna się teraz od indeksu 0 zamiast 1.
Możesz użyć makra 2.1, które jest ważne dla wszystkich wersji 2.1 i nowszych (to dwa znaki podkreślenia przed IPHONE:
Używamy techniki podobnej do tej w większości naszych aplikacji.
Barney
źródło
Miałem powód, aby zrobić to samo (programowo ładować widok z pliku XIB), ale musiałem to zrobić całkowicie w kontekście podklasy podklasy a
UIView
(tj. Bez angażowania kontrolera widoku w jakikolwiek sposób). Aby to zrobić, stworzyłem tę metodę narzędzia:Następnie wywołuję to z
initWithFrame
metody mojej podklasy w następujący sposób:Wysłany do ogólnego zainteresowania; jeśli ktoś zauważy jakiekolwiek problemy bez zrobienia tego w ten sposób, proszę dać mi znać.
źródło
Oto sposób, aby to zrobić w Swift (obecnie pisząc Swift 2.0 w XCode 7 beta 5).
Z
UIView
podklasy ustawionej jako „Klasa niestandardowa” w Konstruktorze interfejsów utwórz metodę taką jak ta (moja podklasa nazywa się RecordingFooterView):Następnie możesz to tak nazwać:
let recordingFooterView = RecordingFooterView.loadFromNib()
źródło
Żadna z odpowiedzi nie wyjaśnia, jak utworzyć samodzielny XIB, który jest źródłem tego pytania. Nie ma
Xcode 4
opcji „Utwórz nowy plik XIB”.Aby to zrobić
Może się to wydawać proste, ale może zaoszczędzić kilka minut na szukanie go, ponieważ słowo „XIB” nigdzie się nie pojawia.
źródło
@AVeryDev
6) Aby dołączyć załadowany widok do widoku kontrolera widoku:
Przypuszczalnie konieczne jest usunięcie go z widoku, aby uniknąć wycieków pamięci.
Aby to wyjaśnić: kontroler widoku ma kilka IBOutletów, z których niektóre są połączone z elementami w oryginalnym pliku końcówki (jak zwykle), a niektóre z elementami z załadowanej końcówki. Obie stalówki mają tę samą klasę właściciela. Załadowany widok nakłada się na oryginalny.
Wskazówka: ustaw krycie widoku głównego w załadowanej wkładce na zero, wtedy nie zasłoni elementów z oryginalnej końcówki.
źródło
Po spędzeniu wielu godzin opracowałem następujące rozwiązanie. Wykonaj następujące kroki, aby utworzyć niestandardowy
UIView
.1) Utwórz klasę myCustomView odziedziczoną z UIView .
2) Utwórz .xib o nazwie myCustomView .
3) Zmień klasę UIView w pliku .xib, przypisz tam klasę myCustomView .
4) Utwórz IBOutlety
5) Załaduj .xib do myCustomView * customView . Użyj następującego przykładowego kodu.
źródło
Najkrótsza wersja:
źródło
Mam konwencję nazywania xibów z widokami w nich takimi samymi jak widok. Tak samo jak w przypadku kontrolera widoku. Nie muszę wtedy zapisywać nazw klas w kodzie. Ładuję UIView z pliku stalówki o tej samej nazwie.
Przykład dla klasy o nazwie MyView.
W swoim kodzie utwórz nowy MyView w następujący sposób:
MyView * myView = [MyView nib_viewFromNibWithOwner: owner];
Oto kategoria tego:
Następnie łączyłem przyciski z działaniami z kontrolera, którego używam, i umieszczałem rzeczy na etykietach, używając gniazd w mojej podklasie widoku niestandardowego.
źródło
Aby programowo załadować widok ze stalówki / xiba w Swift 4:
źródło
W końcu dodałem kategorię do UIView dla tego:
wyjaśnienie tutaj: viewcontroller zmniejsza ładowanie widoku w iOS i Mac
źródło