Kiedy moje „wiersze” UIStackView są zgniatane, generują AutoLayout
ostrzeżenia. Jednak wyświetlają się dobrze i nic więcej nie jest złego poza tego rodzaju logami:
Nie można jednocześnie spełnić ograniczeń. Prawdopodobnie przynajmniej jedno z ograniczeń na poniższej liście jest tym, którego nie chcesz. Spróbuj tego: (1) spójrz na każde ograniczenie i spróbuj dowiedzieć się, którego się nie spodziewasz; (2) znajdź kod, który dodał niechciane ograniczenie lub ograniczenia i napraw go. (Uwaga: jeśli widzisz
NSAutoresizingMaskLayoutConstraints
, że nie rozumiesz, zapoznaj się z dokumentacjąUIView
nieruchomościtranslatesAutoresizingMaskIntoConstraints
) (
Więc nie jestem jeszcze pewien, jak to naprawić, ale wydaje się, że nic nie psuje, poza tym, że jest denerwujący.
Czy ktoś wie, jak to rozwiązać? Co ciekawe, ograniczenia układu dość często są oznaczane jako „ukrywanie UISV” , co oznacza, że być może powinno zignorować minimalne wysokości dla podglądów podrzędnych lub coś w tym przypadku?
źródło
Odpowiedzi:
Ten problem występuje, ponieważ ustawiając widok podrzędny z wewnątrz
UIStackView
na ukryty, najpierw ograniczy jego wysokość do zera, aby go animować.Otrzymałem następujący błąd:
2015-10-01 11:45:13.732 <redacted>[64455:6368084] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: '|':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5be508d0 V:|-(8)-[UISegmentedControl:0x7f7f5bec4180] (Names: '|':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5bdfbda0 'UISV-hiding' V:[UIView:0x7f7f5be69d30(0)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: '|':UIView:0x7f7f5be69d30 )> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
To, co próbowałem zrobić, to umieścić
UIView
wewnątrz mojego,UIStackView
które zawierałoUISegmentedControl
wstawkę o 8 punktów na każdej krawędzi.Kiedy ustawię go na ukryty, będzie próbował ograniczyć widok kontenera do zerowej wysokości, ale ponieważ mam zestaw ograniczeń od góry do dołu, wystąpił konflikt.
Aby rozwiązać ten problem, zmieniłem priorytet ograniczeń 8pt top and bottom z 1000 na 999, aby w
UISV-hiding
razie potrzeby ograniczenie mogło mieć priorytet.źródło
Miałem podobny problem, który nie był łatwy do rozwiązania. W moim przypadku miałem osadzony widok stosu w widoku stosu. Wewnętrzny UIStackView miał dwie etykiety i określony niezerowy odstęp.
Gdy wywołasz addArrangedSubview (), automatycznie utworzy ograniczenia podobne do następujących:
V:|[innerStackView]| | = outerStackView V:|[label1]-(2)-[label2]| | = innerStackView
Teraz, gdy spróbujesz ukryć innerStackView, zostanie wyświetlone ostrzeżenie o niejednoznacznych ograniczeniach.
Aby zrozumieć, dlaczego, zobaczmy najpierw, dlaczego tak się nie dzieje, gdy
innerStackView.spacing
jest równe0
. Kiedy dzwoniszinnerStackView.hidden = true
, @liamnichols miał rację ... wouterStackView
magiczny sposób przechwytuje to połączenie i tworzy ograniczenie ukrywania0
wysokości UISV z priorytetem 1000 (wymagane). Przypuszczalnie ma to na celu umożliwienie animacji elementów w widoku stosu poza widokiem w przypadku wywołania kodu ukrywającego wUIView.animationWithDuration()
bloku. Niestety wydaje się, że nie ma sposobu, aby zapobiec dodaniu tego ograniczenia. Niemniej jednak nie zostanie wyświetlone ostrzeżenie „Nie można jednocześnie spełnić ograniczeń” (USSC), ponieważ zachodzą następujące sytuacje:Widać wyraźnie, że te 4 ograniczenia mogą być spełnione. Widok stosu po prostu wygładza wszystko do piksela o wysokości 0.
Teraz wraca do buggy przykład, jeśli mamy ustawić
spacing
do2
mamy teraz te ograniczenia:Widok stosu nie może jednocześnie mieć wysokości 0 pikseli i mieć zawartość 2 pikseli. Ograniczenia nie mogą być spełnione.
Uwaga: możesz zobaczyć to zachowanie na prostszym przykładzie. Po prostu dodaj UIView do widoku stosu jako uporządkowany widok podrzędny. Następnie ustaw ograniczenie wysokości dla tego UIView z priorytetem 1000. Teraz spróbuj zadzwonić do hide.
Uwaga: z jakiegoś powodu dzieje się tak tylko wtedy, gdy mój widok stosu był podwidokiem UICollectionViewCell lub UITableViewCell. Jednak nadal można odtworzyć to zachowanie poza komórką, wywołując
innerStackView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
następną pętlę uruchamiania po ukryciu widoku stosu wewnętrznego.Uwaga: Nawet jeśli spróbujesz wykonać kod w UIView.performWithoutAnimations, widok stosu nadal doda ograniczenie wysokości 0, co spowoduje ostrzeżenie USSC.
Istnieją co najmniej 3 rozwiązania tego problemu:
spacing
0. Jest to denerwujące, ponieważ musisz odwrócić ten proces (i zapamiętać oryginalne odstępy) za każdym razem, gdy ponownie wyświetlasz zawartość.removeFromSuperview
. Jest to jeszcze bardziej irytujące, ponieważ odwracając proces, musisz pamiętać, gdzie włożyć usunięty element. Możesz zoptymalizować, wywołując tylko removeArrangedSubview, a następnie ukrywając, ale nadal trzeba wykonać wiele czynności księgowych.spacing
różną od zera ) w UIView. Określ co najmniej jedno ograniczenie jako niewymagany priorytet (999 lub mniej). To najlepsze rozwiązanie, ponieważ nie musisz prowadzić żadnej księgowości. W moim przykładzie utworzyłem górne, wiodące i końcowe ograniczenia na poziomie 1000 między widokiem stosu a widokiem opakowania, a następnie utworzyłem ograniczenie 999 od dołu widoku stosu do widoku opakowania. W ten sposób, gdy zewnętrzny widok stosu tworzy ograniczenie zerowej wysokości, ograniczenie 999 zostaje zerwane i nie widać ostrzeżenia USSC. (Uwaga: jest to podobne do rozwiązania w przypadku ustawienia wartości ContentView.translatesAutoResizingMaskToConstraints podklasy UICollectionViewCell nafalse
)Podsumowując, przyczyny takiego zachowania to:
Gdyby Apple albo (1) pozwolił ci określić priorytet ograniczeń (zwłaszcza odstępników), albo (2) pozwolił ci zrezygnować z automatycznego ograniczenia ukrywania UISV , problem ten zostałby łatwo rozwiązany.
źródło
UIStackView
dzieckoUIStackView
musi być owinięte w coś,UIView
czy tylko to, które chcesz ukryć / odkryć?UIStackView
są zwykle tajemnicze i trudne do zrozumienia.W większości przypadków ten błąd można rozwiązać, obniżając priorytet ograniczeń w celu wyeliminowania konfliktów.
źródło
Gdy ustawisz widok jako ukryty, program
UIStackview
spróbuje go ożywić. Jeśli chcesz uzyskać ten efekt, musisz ustawić odpowiedni priorytet dla ograniczeń, aby nie kolidowały (jak wielu sugerowało powyżej).Jeśli jednak nie zależy ci na animacji (być może ukrywasz ją w ViewDidLoad), możesz prostą metodą,
removeFromSuperview
która będzie miała ten sam efekt, ale bez żadnych problemów z ograniczeniami, ponieważ zostaną one usunięte wraz z widokiem.źródło
W oparciu o odpowiedź @ Senseful, oto rozszerzenie UIStackView do zawijania widoku stosu w widoku i stosowania ograniczeń, które zaleca:
/// wraps in a `UIView` to prevent autolayout warnings when a stack view with spacing is placed inside another stack view whose height might be zero (usually due to `hidden` being `true`). /// See http://stackoverflow.com/questions/32428210 func wrapped() -> UIView { let wrapper = UIView() translatesAutoresizingMaskIntoConstraints = false wrapper.addSubview(self) for attribute in [NSLayoutAttribute.Top, .Left, .Right, .Bottom] { let constraint = NSLayoutConstraint(item: self, attribute: attribute, relatedBy: .Equal, toItem: wrapper, attribute: attribute, multiplier: 1, constant: 0) if attribute == .Bottom { constraint.priority = 999 } wrapper.addConstraint(constraint) } return wrapper }
Zamiast dodawać swój
stackView
, użyjstackView.wrapped()
.źródło
Po pierwsze, jak sugerowali inni, upewnij się, że ograniczenia, które możesz kontrolować, tj. Nie ograniczenia właściwe dla UIStackView, mają ustawiony priorytet 999, aby można je było przesłonić, gdy widok jest ukryty.
Jeśli problem nadal występuje, prawdopodobnie jest on spowodowany odstępami w ukrytych StackViews. Moim rozwiązaniem było dodanie UIView jako odstępnika i ustawienie odstępu UIStackView na zero. Następnie ustaw ograniczenia View.height lub View.width (w zależności od stosu pionowego lub poziomego) na odstępy StackView.
Następnie dostosuj priorytety przytulania treści i odporności na kompresję nowo dodanych widoków. Może być również konieczna zmiana dystrybucji nadrzędnego StackView.
Wszystkie powyższe czynności można wykonać w programie Interface Builder. Być może będziesz musiał programowo ukryć / odkryć niektóre z nowo dodanych widoków, aby uniknąć niepożądanych odstępów.
źródło
Niedawno zmagałem się z błędami automatycznego układu podczas ukrywania pliku
UIStackView
. Zamiast zajmować się księgowaniem i pakowaniem stosówUIViews
, zdecydowałem się stworzyć ujście dla siebieparentStackView
i dla dzieci, które chcę ukryć / odkryć.@IBOutlet weak var parentStackView: UIStackView! @IBOutlet var stackViewNumber1: UIStackView! @IBOutlet var stackViewNumber2: UIStackView!
Oto jak wygląda mój ParentStack w scenorysie:
Ma 4 dzieci i każde z nich ma w sobie kilka widoków stosu. Gdy ukryjesz widok stosu, jeśli zawiera on elementy interfejsu użytkownika, które są również widokami stosu, zobaczysz strumień błędów automatycznego układu. Zamiast się ukrywać, zdecydowałem się je usunąć.
W moim przykładzie
parentStackViews
zawiera tablicę 4 elementów: widok górnego stosu, widok stosu, numer 1, widok stosu numer 2 i przycisk zatrzymania. Ich indeksy warrangedSubviews
to odpowiednio 0, 1, 2 i 3. Kiedy chcę go ukryć, po prostu usuwam go zparentStackView's
arrangedSubviews
tablicy. Ponieważ nie jest słaby, pozostaje w pamięci i możesz później po prostu umieścić go z powrotem w wybranym indeksie. Nie uruchamiam go ponownie, więc po prostu wisi, dopóki nie będzie potrzebny, ale nie nadyma pamięci.Więc w zasadzie możesz ...
1) Przeciągnij IBOutlets dla swojego stosu nadrzędnego i dzieci, które chcesz ukryć / odkryć, do scenorysu.
2) Jeśli chcesz je ukryć, usuń stos, który chcesz ukryć z
parentStackView's
arrangedSubviews
tablicy.3) Zadzwoń za
self.view.layoutIfNeeded()
pomocąUIView.animateWithDuration
.Zwróć uwagę, że ostatnie dwa stackViews nie są
weak
. Musisz je mieć pod ręką, gdy je odkryjesz.Powiedzmy, że chcę ukryć stackViewNumber2:
parentStackView.removeArrangedSubview(stackViewNumber2) stackViewNumber2.removeFromSuperview()
Następnie animuj to:
UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil)
Jeśli chcesz „odkryć”
stackViewNumber2
później, możesz po prostu wstawić go do odpowiedniegoparentStackView
arrangedSubViews
indeksu i animować aktualizację.parentStackView.removeArrangedSubview(stackViewNumber1) stackViewNumber1.removeFromSuperview() parentStackView.insertArrangedSubview(stackViewNumber2, at: 1) // Then animate it UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil)
Okazało się, że jest to o wiele łatwiejsze niż prowadzenie księgowości w zakresie ograniczeń, majstrowanie przy priorytetach itp.
Jeśli masz coś, co chcesz domyślnie ukryć, możesz po prostu ułożyć to w scenorysie, usunąć
viewDidLoad
i zaktualizować bez użycia animacjiview.layoutIfNeeded()
.źródło
Wystąpiły te same błędy z osadzonymi widokami stosu, chociaż wszystko działało dobrze w czasie wykonywania.
Rozwiązałem błędy ograniczenia, ukrywając najpierw wszystkie widoki stosu podrzędnego (ustawienie
isHidden = true
) przed ukryciem widoku stosu nadrzędnego.Nie wymagało to całej złożoności usuwania widoków podrzędnych i utrzymywania indeksu, gdy trzeba je ponownie dodać.
Mam nadzieję że to pomoże.
źródło
Senseful dostarczyło doskonałej odpowiedzi na przyczynę powyższego problemu, więc przejdę od razu do rozwiązania.
Wszystko, co musisz zrobić, to ustawić priorytet wszystkich ograniczeń stackView na mniej niż 1000 (999 wykona pracę). Na przykład, jeśli stackView jest ograniczony w lewo, w prawo, na górze i na dole do swojego superview, wówczas wszystkie 4 ograniczenia powinny mieć priorytet niższy niż 1000.
źródło
Możliwe, że utworzyłeś ograniczenie podczas pracy z pewną klasą wielkości (np. WCompact hRegular), a następnie utworzyłeś duplikat po przełączeniu na inną klasę wielkości (np. WAny hAny). sprawdź ograniczenia obiektów UI w różnych klasach wielkości i zobacz, czy nie ma anomalii z ograniczeniami. powinieneś zobaczyć czerwone linie wskazujące na kolidujące wiązania. Nie mogę umieścić zdjęcia, dopóki nie zdobędę 10 punktów reputacji. Przepraszam: /
źródło
Chciałem ukryć całe UIStackView na raz, ale otrzymywałem te same błędy co OP, to naprawiło to dla mnie:
for(UIView *currentView in self.arrangedSubviews){ for(NSLayoutConstraint *currentConstraint in currentView.constraints){ [currentConstraint setPriority:999]; } }
źródło
priority = 1000
) na niewymagane (priority <= 999
).Miałem rząd przycisków z ograniczeniem wysokości. Dzieje się tak, gdy jeden przycisk jest ukryty. Ustawienie priorytetu ograniczenia wysokości tego przycisku na 999 rozwiązało problem.
źródło
Ten błąd nie ma nic wspólnego z UIStackView. Dzieje się tak, gdy masz ograniczenia konfliktu z tymi samymi priorytetami. Na przykład, jeśli masz ograniczenie, które określa, że szerokość widoku wynosi 100, a inne ograniczenie w tym samym czasie stwierdza, że szerokość widoku wynosi 25% jego kontenera. Oczywiście istnieją dwa sprzeczne ograniczenia. Rozwiązaniem jest usunięcie jednego z nich.
źródło
NOP z [mySubView removeFromSuperview]. Mam nadzieję, że mogłoby to komuś pomóc :)
źródło