Oryginalne rozwiązanie
- Stworzyłem XIB i klasę o nazwie SomeView (dla wygody i czytelności użyłem tej samej nazwy). Oparłem oba na UIView.
- W XIB zmieniłem klasę „Właściciel pliku” na SomeView (w inspektorze tożsamości).
- Utworzyłem punkt sprzedaży UIView w SomeView.swift, łącząc go z widokiem najwyższego poziomu w pliku XIB (dla wygody nazwałem go „widokiem”). Następnie w razie potrzeby dodałem inne wyjścia do innych formantów w pliku XIB.
- w SomeView.swift załadowałem XIB wewnątrz inicjatora "init with code". Nie ma potrzeby przypisywania czegokolwiek do „siebie”. Zaraz po załadowaniu XIB wszystkie gniazda są podłączone, w tym widok z góry. Jedyne, czego brakuje, to dodać widok z góry do hierarchii widoków:
.
class SomeView: UIView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSBundle.mainBundle().loadNibNamed("SomeView", owner: self, options: nil)
self.addSubview(self.view); // adding the top level view to the view hierarchy
}
...
}
Zauważ, że w ten sposób otrzymuję klasę, która ładuje się ze stalówki. Mógłbym wtedy użyć SomeView jako klasy, ilekroć UIView może być użyty w projekcie (w konstruktorze interfejsu lub programowo).
Aktualizacja - przy użyciu składni Swift 3
Ładowanie xib w następującym rozszerzeniu jest zapisywane jako metoda instancji, która może być następnie używana przez inicjator, taki jak powyższy:
extension UIView {
@discardableResult // 1
func fromNib<T : UIView>() -> T? { // 2
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else { // 3
// xib not loaded, or its top view is of the wrong type
return nil
}
self.addSubview(contentView) // 4
contentView.translatesAutoresizingMaskIntoConstraints = false // 5
contentView.layoutAttachAll(to: self) // 6
return contentView // 7
}
}
- Używanie odrzucalnej wartości zwracanej, ponieważ zwracany widok nie jest w większości interesujący dla dzwoniącego, gdy wszystkie gniazda są już połączone.
- Jest to metoda ogólna, która zwraca opcjonalny obiekt typu UIView. Jeśli załadowanie widoku nie powiedzie się, zwraca nil.
- Próba załadowania pliku XIB o tej samej nazwie, co bieżąca instancja klasy. Jeśli to się nie powiedzie, zwracane jest nil.
- Dodawanie widoku najwyższego poziomu do hierarchii widoków.
- Ta linia zakłada, że używamy ograniczeń do rozmieszczenia widoku.
- Ta metoda dodaje górne, dolne, wiodące i końcowe ograniczenia - dołączanie widoku do „siebie” ze wszystkich stron (szczegóły: https://stackoverflow.com/a/46279424/2274829 )
- Wracam do widoku najwyższego poziomu
A metoda wywołująca może wyglądać następująco:
final class SomeView: UIView { // 1.
required init?(coder aDecoder: NSCoder) { // 2 - storyboard initializer
super.init(coder: aDecoder)
fromNib() // 5.
}
init() { // 3 - programmatic initializer
super.init(frame: CGRect.zero) // 4.
fromNib() // 6.
}
// other methods ...
}
- SomeClass to podklasa UIView, która ładuje swoją zawartość z pliku SomeClass.xib. Słowo kluczowe „końcowe” jest opcjonalne.
- Inicjator, gdy widok jest używany w scenorysie (pamiętaj, aby użyć SomeClass jako niestandardowej klasy widoku storyboardu).
- Inicjator, gdy widok jest tworzony programowo (np. „Let myView = SomeView ()”).
- Używanie ramki zawierającej same zera, ponieważ ten widok jest układany przy użyciu automatycznego układu. Zauważ, że metoda "init (frame: CGRect) {..}" nie jest tworzona niezależnie, ponieważ auto-layout jest używany wyłącznie w naszym projekcie.
- & 6. Ładowanie pliku xib przy użyciu rozszerzenia.
Kredyt: Użycie ogólnego rozszerzenia w tym rozwiązaniu zostało zainspirowane poniższą odpowiedzią Roberta.
Edytuj
Zmieniając „widok” na „contentView”, aby uniknąć nieporozumień. Zmieniono także indeks tablicy na „.first”.
File's Owner
trafiona ... Dzięki!