Firma Apple dość jasno zdefiniowała sposób tworzenia podklas UIView
w dokumencie.
Sprawdź poniższą listę, a zwłaszcza spójrz na initWithFrame:
i layoutSubviews
. Pierwsza z nich jest przeznaczona do ustawienia ramki, UIView
podczas gdy druga służy do ustawienia ramki i układu jej podglądów.
Pamiętaj również, że initWithFrame:
jest ona wywoływana tylko wtedy, gdy tworzysz instancję w sposób UIView
programowy. Jeśli ładujesz go z pliku nib (lub storyboardu), initWithCoder:
zostanie użyty. A w initWithCoder:
ramce nie został jeszcze obliczony, więc nie można zmodyfikować ramkę skonfigurowanej w konstruktorze Interface. Jak zasugerowano w tej odpowiedzi , możesz pomyśleć o dzwonieniu initWithFrame:
z initWithCoder:
w celu ustawienia ramki.
Na koniec, jeśli ładujesz UIView
ze stalówki (lub storyboardu), masz również awakeFromNib
możliwość wykonania niestandardowych inicjalizacji ramki i układu, ponieważ kiedy awakeFromNib
jest wywoływany, gwarantuje się, że każdy widok w hierarchii został cofnięty z archiwum i zainicjowany.
Z dokumentu z NSNibAwaking
(obecnie zastąpionego przez dokument z awakeFromNib
):
Wiadomości do innych obiektów mogą być bezpiecznie wysyłane z poziomu awakeFromNib - do tego czasu mamy pewność, że wszystkie obiekty zostaną przywrócone z archiwum i zainicjowane (choć niekoniecznie przebudzone, oczywiście)
Warto również zauważyć, że w przypadku autoukładu nie należy jawnie ustawiać ramki widoku. Zamiast tego należy określić zestaw wystarczających ograniczeń, aby ramka była automatycznie obliczana przez silnik układu.
Prosto z dokumentacji :
Metody do zastąpienia
Inicjalizacja
initWithFrame:
Zaleca się wdrożenie tej metody. Oprócz tej metody lub zamiast niej można również zaimplementować niestandardowe metody inicjowania.
initWithCoder:
Zaimplementuj tę metodę, jeśli ładujesz widok z pliku nib programu Interface Builder, a widok wymaga niestandardowej inicjalizacji.
layerClass
Zaimplementuj tę metodę tylko wtedy, gdy chcesz, aby Twój widok używał innej warstwy animacji podstawowej dla swojego magazynu zapasowego. Na przykład, jeśli używasz OpenGL ES do rysowania, chciałbyś zastąpić tę metodę i zwrócić klasę CAEAGLLayer.
Rysowanie i drukowanie
drawRect:
Zaimplementuj tę metodę, jeśli Twój widok rysuje zawartość niestandardową. Jeśli widok nie zawiera żadnego niestandardowego rysunku, unikaj zastępowania tej metody.
drawRect:forViewPrintFormatter:
Zastosuj tę metodę tylko wtedy, gdy chcesz inaczej narysować zawartość widoku podczas drukowania.
Ograniczenia
requiresConstraintBasedLayout
Zaimplementuj tę metodę klasy, jeśli klasa widoku wymaga ograniczeń do prawidłowego działania.
updateConstraints
Zaimplementuj tę metodę, jeśli Twój widok wymaga tworzenia niestandardowych ograniczeń między widokami podrzędnymi.
alignmentRectForFrame:
, frameForAlignmentRect:
Zaimplementuj te metody, aby zastąpić sposób dopasowania widoków do innych widoków.
Układ
sizeThatFits:
Zaimplementuj tę metodę, jeśli chcesz, aby widok miał inny domyślny rozmiar niż normalnie podczas operacji zmiany rozmiaru. Na przykład, możesz użyć tej metody, aby zapobiec zmniejszaniu się widoku do punktu, w którym podwidoki nie mogą być poprawnie wyświetlane.
layoutSubviews
Zaimplementuj tę metodę, jeśli potrzebujesz dokładniejszej kontroli nad układem widoków podrzędnych, niż zapewniają to ograniczenia lub zachowania autorezyzacji.
didAddSubview:
, willRemoveSubview:
Zaimplementuj te metody w razie potrzeby, aby śledzić dodawanie i usuwanie podglądów podrzędnych.
willMoveToSuperview:
, didMoveToSuperview
Zaimplementuj te metody w razie potrzeby, aby śledzić ruch bieżącego widoku w hierarchii widoków.
willMoveToWindow:
, didMoveToWindow
Zaimplementuj te metody w razie potrzeby, aby śledzić ruch widoku do innego okna.
Obsługa zdarzeń:
touchesBegan:withEvent:
, touchesMoved:withEvent:
, touchesEnded:withEvent:
, touchesCancelled:withEvent:
Wdrożenie tych metod, jeśli chcesz obsługiwać zdarzenia dotykowe bezpośrednio. (W przypadku wprowadzania za pomocą gestów użyj rozpoznawania gestów).
gestureRecognizerShouldBegin:
Zaimplementuj tę metodę, jeśli Twój widok bezpośrednio obsługuje zdarzenia dotyku i może chcieć uniemożliwić dołączonym modułom rozpoznawania gestów wyzwalanie dodatkowych akcji.
Gabriele Petronella
źródło
layoutSubviews
?To wciąż pojawia się wysoko w Google. Poniżej znajduje się zaktualizowany przykład dla Swift.
didLoad
Funkcja pozwala umieścić swój kod niestandardowy inicjalizacji. Jak wspominali inni,didLoad
zostanie wywołany, gdy widok zostanie utworzony programowo za pośrednictweminit(frame:)
lub gdy deserializator XIB połączy szablon XIB z widokiem za pomocąinit(coder:)
źródło
draw
metodę?W dokumentacji Apple znajduje się przyzwoite podsumowanie , które jest dobrze omówione w bezpłatnym kursie Stanforda dostępnym w iTunes. Przedstawiam moją wersję TL; DR tutaj:
Jeśli twoja klasa składa się głównie z podglądów podrzędnych, właściwym miejscem do ich przydzielania są
init
metody. W przypadku widoków istnieją dwie różneinit
metody, które można wywołać, w zależności od tego, czy Twój widok jest tworzony z kodu, czy z końcówki / serii ujęć. Co mogę zrobić, to napisać własnysetup
sposób, a następnie wywołać ją z obuinitWithFrame:
iinitWithCoder:
metod.Jeśli rysujesz niestandardowy, rzeczywiście chcesz nadpisać
drawRect:
w swoim widoku. Jeśli jednak Twój widok niestandardowy jest głównie kontenerem dla podglądów podrzędnych, prawdopodobnie nie będziesz musiał tego robić.Zastąp tylko,
layoutSubViews
jeśli chcesz zrobić coś takiego, jak dodanie lub usunięcie widoku podrzędnego, w zależności od tego, czy jesteś w orientacji pionowej czy poziomej. W przeciwnym razie powinieneś być w stanie zostawić to w spokoju.źródło
layoutSubViews
, zadziałało.layoutSubviews
ma na celu ustawienie ramki na widokach potomnych, a nie na samym widoku.W przypadku
UIView
, wyznaczony konstruktor jest zwykleinitWithFrame:(CGRect)frame
i powinieneś ustawić ramkę tam (lub winitWithCoder:
), prawdopodobnie ignorując przekazaną wartość ramki. Możesz też podać innego konstruktora i ustawić tam ramkę.źródło
awakeFromNib