Nie mówię o właściwości frame, ponieważ z tego można uzyskać tylko rozmiar widoku w xib. Mówię o tym, kiedy rozmiar widoku jest zmieniany z powodu jego ograniczeń (może po obróceniu lub w odpowiedzi na zdarzenie). Czy jest sposób, aby uzyskać jego aktualną szerokość i wysokość?
Próbowałem iterować przez jego ograniczenia, szukając ograniczeń szerokości i wysokości, ale nie jest to zbyt jasne i kończy się niepowodzeniem, gdy istnieją wewnętrzne ograniczenia (ponieważ nie mogę rozróżnić między nimi). Działa to tylko wtedy, gdy faktycznie mają ograniczenia dotyczące szerokości i wysokości, których nie mają, jeśli polegają na innych ograniczeniach w celu zmiany rozmiaru.
Dlaczego jest to dla mnie takie trudne. ARG!
ios
autolayout
yuf
źródło
źródło
Odpowiedzi:
Odpowiedź jest
[view layoutIfNeeded]
.Dlatego:
Wciąż uzyskujesz aktualną szerokość i wysokość widoku, sprawdzając
view.bounds.size.width
iview.bounds.size.height
(lub ramkę, która jest równoważna, chyba że grasz zview.transform
).Jeśli chcesz mieć szerokość i wysokość sugerowaną przez istniejące ograniczenia, odpowiedzią nie jest ręczne sprawdzanie ograniczeń, ponieważ wymagałoby to ponownego zaimplementowania całej logiki rozwiązywania ograniczeń systemu automatycznego układu w celu ich zinterpretowania. ograniczenia. Zamiast tego powinieneś po prostu poprosić auto layout o zaktualizowanie tego układu , tak aby rozwiązał on ograniczenia i zaktualizował wartość view.bounds z poprawnym rozwiązaniem, a następnie sprawdzisz view.bounds.
Jak poprosić automatyczny układ o aktualizację układu? Zadzwoń,
[view setNeedsLayout]
jeśli chcesz, aby automatyczny układ zaktualizował układ na następnym zakręcie pętli uruchamiania.Jednakże, jeśli chcesz, aby natychmiast zaktualizować układ, dzięki czemu można natychmiast uzyskać dostęp do nowych granic cenią później w ciągu bieżącej funkcji, lub w innym miejscu przed przełomie pętli biegu, to trzeba zadzwonić
[view setNeedsLayout]
i[view layoutIfNeeded]
.Zadałeś drugie pytanie: „Jak mogę zmienić ograniczenie wysokości / szerokości, jeśli nie mam do niego bezpośredniego odniesienia?”.
Jeśli tworzysz ograniczenie w IB, najlepszym rozwiązaniem jest utworzenie IBOutlet w kontrolerze widoku lub widoku, aby mieć do niego bezpośrednie odniesienie. Jeśli utworzyłeś ograniczenie w kodzie, powinieneś trzymać odwołanie w wewnętrznej słabej właściwości w czasie, gdy je tworzyłeś. Jeśli ktoś inny utworzył ograniczenie, musisz je znaleźć, sprawdzając właściwość review.constraints w widoku i prawdopodobnie całą hierarchię widoków oraz implementując logikę, która znajduje kluczowe NSLayoutConstraint. Jest to prawdopodobnie niewłaściwa droga, ponieważ wymaga również skutecznego określenia, które konkretne ograniczenie określa rozmiar granic, podczas gdy nie ma gwarancji, że będzie prosta odpowiedź na to pytanie. Ostateczna wartość ograniczeń może być rozwiązaniem bardzo skomplikowanego systemu wielu ograniczeń,
źródło
layoutIfNeeded
jest świetny i sprawi, że rama będzie natychmiast dostępna. Jednak wymusi również renderowanie ograniczeń na wszystkich widokach w poddrzewach widoku, na którym jest wywoływana. Jeśli na przykład dodajesz widoki programowo i wywołujeszlayoutIfNeeded
je wszystkie w swojej procedurze rekurencyjnej, może się okazać, że hierarchia widoków renderuje się bardzo wolno. (Nauczyłem się tego na własnej skórze) Jak wspomniano w doskonałej odpowiedzi, „setNeedsLayout” jest bardziej wydajne i udostępni ramkę przy następnym przejściu układu, co idealnie dzieje się w około 1/60 sekundy.initWithCoder
?Miałem podobny problem, w którym musiałem dodać górną i dolną granicę do pliku
UITableView
który zmienia rozmiar na podstawie ustawień ograniczeń wUIStoryboard
. Udało mi się uzyskać dostęp do zaktualizowanych ograniczeń za pomocą- (void)viewDidLayoutSubviews
. Jest to przydatne, ponieważ nie ma potrzeby tworzenia podklasy widoku i nadpisywania jego metody układu.Bez wywoływania metody z
viewDidLayoutSubview
metody, tylko górna krawędź jest rysowana poprawnie, ponieważ dolna krawędź jest gdzieś poza ekranem.źródło
[super viewDidLayoutSubviews];
Dla tych, którzy mogą nadal borykać się z takimi problemami, zwłaszcza z TableviewCell.
Po prostu zastąp metodę:
W przypadku UITableViewCell lub UICollectionViewCell utwórz podklasę komórki i nadpisz tę samą metodę:
źródło
Użyj
-(void)viewWillAppear:(BOOL)animated
i zadzwoń[self.view layoutIfNeeded];
- to działa, próbowałem.ponieważ jeśli
-(void)viewDidLayoutSubviews
go użyjesz , zadziała na pewno, ale ta metoda jest wywoływana za każdym razem, gdy twój interfejs użytkownika wymaga aktualizacji / zmian. Który będzie trudny do opanowania. Klawisz programowy to użycie zmiennej bool, aby uniknąć takiej pętli wywołań. lepsze wykorzystanieviewWillAppear
. Funkcja RememberviewWillAppear
zostanie również wywołana, jeśli widok zostanie ponownie załadowany (bez ponownego przydzielania).źródło
Ramka jest nadal aktualna. Ostatecznie widok wykorzystuje swoją właściwość frame do układania się. Oblicza tę klatkę na podstawie wszystkich ograniczeń. Ograniczenia są używane tylko dla początkowego układu (i za każdym razem, gdy layoutSubviews jest wywoływany w widoku, tak jak po obróceniu). Następnie informacje o pozycji znajdują się we właściwości ramki. A może widzisz inaczej?
źródło