Skonfigurowałem wiele zestawów ograniczeń w IB i chciałbym programowo przełączać się między nimi w zależności od stanu. Istnieje constraintsA
kolekcja outlet, z których wszystkie są oznaczone jako zainstalowane z IB oraz constraintsB
kolekcja outlet, z których wszystkie są odinstalowane w IB.
Mogę programowo przełączać się między tymi dwoma zestawami w następujący sposób:
NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)
Ale ... Nie wiem, kiedy to zrobić. Wygląda na to, że kiedyś powinienem to zrobić viewDidLoad
, ale nie mogę tego zmusić. Próbowałem dzwonić view.updateConstraints()
i view.layoutSubviews()
po ustawieniu ograniczeń, ale bezskutecznie.
Zauważyłem, że jeśli ustawię ograniczenia, viewDidLayoutSubviews
wszystko działa zgodnie z oczekiwaniami. Chyba chciałbym wiedzieć dwie rzeczy ...
- Dlaczego otrzymuję takie zachowanie?
- Czy można aktywować / dezaktywować ograniczenia z viewDidLoad?
ios
swift
uiview
autolayout
nslayoutconstraint
tybro0103
źródło
źródło
Odpowiedzi:
Włączam i dezaktywuję
NSLayoutConstraints
wviewDidLoad
i nie mam z tym żadnych problemów. Więc to działa. Musi istnieć różnica w konfiguracji między Twoją aplikacją a moją :-)Opiszę tylko moją konfigurację - może da ci wskazówkę:
@IBOutlets
wszystkie ograniczenia, które muszę aktywować / dezaktywować.ViewController
zapisuję ograniczenia we właściwościach klas, które nie są słabe. Powodem tego jest to, że stwierdziłem, że po dezaktywacji ograniczenia nie mogłem go ponownie aktywować - było zero. Tak więc wydaje się, że jest usuwany po dezaktywacji.NSLayoutConstraint.deactivate/activate
tak jak ty, zamiast tego używamconstraint.active = YES
/NO
.view.layoutIfNeeded()
.źródło
.active = false
spodziewając się, że zostaną zignorowane, dopóki nie ustawię ich jako aktywnych.Być może można sprawdzić swoje
@properties
wymienićweak
zstrong
.Czasami to dlatego , że
active = NO
ustawioneself.yourConstraint = nil
, aby nie można było użyćself.yourConstraint
ponownie.źródło
weak
i to wystarczy.źródło
Uważam, że problem, którego doświadczasz, jest spowodowany tym, że ograniczenia nie są dodawane do ich widoków, dopóki nie
viewDidLoad()
zostanie wywołana funkcja AFTER . Masz kilka opcji:A) Możesz połączyć swoje ograniczenia układu z IBOutlet i uzyskać do nich dostęp w swoim kodzie za pomocą tych odwołań. Ponieważ gniazda są podłączone przed
viewDidLoad()
uruchomieniem, ograniczenia powinny być dostępne i można je tam nadal aktywować i dezaktywować.B) Jeśli chcesz użyć
constraints()
funkcji UIView, aby uzyskać dostęp do różnych ograniczeń, musisz poczekać naviewDidLayoutSubviews()
rozpoczęcie i zrobić to tam, ponieważ jest to pierwszy punkt po utworzeniu kontrolera widoku z końcówki, że będzie on miał zainstalowane ograniczenia. Nie zapomnij zadzwonić,layoutIfNeeded()
kiedy skończysz. Ma to tę wadę, że przebieg układu zostanie wykonany dwukrotnie, jeśli są jakieś zmiany do zastosowania i należy upewnić się, że nie ma możliwości wywołania nieskończonej pętli.Krótkie ostrzeżenie: wyłączone ograniczenia NIE są zwracane przez
constraints()
metodę! Oznacza to, że jeśli NIE wyłączysz ograniczenia z zamiarem ponownego włączenia go później, będziesz musiał zachować do niego odniesienie.C) Możesz zapomnieć o podejściu do scenorysu i zamiast tego ręcznie dodać ograniczenia. Ponieważ robisz to w trakcie
viewDidLoad()
, zakładam, że intencją jest zrobienie tego tylko raz przez cały okres użytkowania obiektu, a nie zmiana układu w locie, więc powinna to być akceptowalna metoda.źródło
Możesz również dostosować
priority
właściwość, aby je „włączyć” i „wyłączyć” (na przykład 750 wartość do włączenia i 250 do wyłączenia). Z jakiegoś powodu zmianaactive
BOOL nie miała żadnego wpływu na mój interfejs użytkownika. Nie ma potrzebylayoutIfNeeded
i można to ustawić i zmienić w viewDidLoad lub w dowolnym momencie po tym.źródło
viewWillTransition(to:, with:)
lubviewWillLayoutSubviews()
i możesz zachować wszystkie alternatywne ograniczenia jako „zainstalowane” w scenorysie. Priorytet ograniczenia nie może zmienić się z niewymaganego na wymagany, dlatego użyj poniższych wartości1000
. Z drugiej strony, aktywowanie (dodawanie) i dezaktywowanie (usuwanie) ograniczeń działa tylkoviewDidLayoutSubviews()
i wymaga zachowaniastrong
@IBOutlet
odniesień doNSLayoutConstraint
-s.Właściwy czas na dezaktywację nieużywanych ograniczeń:
Pamiętaj, że
viewWillLayoutSubviews
można to wywołać wiele razy, więc nie ma tu ciężkich obliczeń, ok?Uwaga: jeśli chcesz później reaktywować niektóre z ograniczeń, zawsze przechowuj
strong
do nich odniesienie.źródło
viewDidLayoutSubviews()
. Dostosowywanie ograniczeńviewWillLayoutSubviews()
w moim przypadku nie działa.Podczas tworzenia widoku wywoływane są w kolejności następujące metody cyklu życia:
A teraz do twoich pytań.
Odpowiedź: Ponieważ kiedy próbujesz ustawić ograniczenia dla widoków w
viewDidLoad
widoku, nie ma swoich granic, dlatego nie można ich ustawić. Dopiero potemviewDidLayoutSubviews
granice widoku są sfinalizowane.Odpowiedź: Nie. Powód wyjaśniony powyżej.
źródło
Odkryłem, że tak długo, jak ustawiasz ograniczenia na normalne w nadpisywaniu
- (void)updateConstraints
(cel c), zstrong
odniesieniem do początkowości użytych ograniczeń aktywnych i nieaktywnych. W innym miejscu cyklu widoku dezaktywuj i / lub aktywuj to, czego potrzebujesz, a następnie dzwoniąclayoutIfNeeded
, nie powinieneś mieć problemów.Najważniejsze jest, aby nie używać ciągle nadpisywania
updateConstraints
i oddzielać aktywacji ograniczeń, o ile wywołujeszupdateConstraint
s po pierwszej inicjalizacji i układzie. Wydaje się, że ma to znaczenie po tym, gdzie w cyklu widoku.źródło