Zaprojektowałem moją niestandardową komórkę w IB, podklasowałem ją i połączyłem swoje gniazdka z moją niestandardową klasą. Mam trzy podstrony w treści komórki, które są: UIView (cdView) i dwie etykiety (titleLabel i emailLabel). W zależności od danych dostępnych dla każdego wiersza, czasami chcę mieć UIView i dwie etykiety wyświetlane w mojej komórce, a czasem tylko dwie etykiety. Staram się w ten sposób ustawić ograniczenia, jeśli ustawię właściwość UIView na ukrytą lub usunę ją z podglądu, dwie etykiety zostaną przesunięte w lewo. Próbowałem ustawić wiodące ograniczenie UIView na Superview (zawartość komórki) dla 10px i UILabels wiodące ograniczenia dla 10 px do następnego widoku (UIView). Później w moim kodzie
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(IndexPath *)indexPath {
...
Record *record = [self.records objectAtIndex:indexPath.row];
if ([record.imageURL is equalToString:@""]) {
cell.cdView.hidden = YES;
}
Chowam swoją komórkę. CdView i chciałbym, aby etykiety przesunęły się w lewo, jednak pozostają one w tej samej pozycji w komórce. Próbowałem usunąć cell.cdView z podglądu, ale to też nie działało. Załączam obraz, aby wyjaśnić, o co mi chodzi.
Wiem, jak to zrobić programowo i nie szukam tego rozwiązania. Chcę ustawić ograniczenia w IB i oczekuję, że moje widoki podrzędne będą się dynamicznie przemieszczać, jeśli inne widoki zostaną usunięte lub ukryte. Czy można to zrobić w IB z automatycznym układem?
.....
Odpowiedzi:
Jest to możliwe, ale będziesz musiał wykonać trochę dodatkowej pracy. Najpierw trzeba usunąć kilka koncepcyjnych rzeczy:
W twoim przypadku prawdopodobnie oznacza to:
To, co musisz zrobić, to rozsądnie przeciążyć swoje etykiety. Pozostaw istniejące ograniczenia (przestrzeń 10 punktów do drugiego widoku) w spokoju, ale dodaj kolejne ograniczenie: ustaw lewą krawędź etykiet 10 punktów od lewej krawędzi ich podglądu z niepotrzebnym priorytetem (domyślnie wysoki priorytet prawdopodobnie będzie działał dobrze).
Następnie, jeśli chcesz, aby przesunęli się w lewo, całkowicie usuń lewy widok. Obowiązkowe ograniczenie 10 punktów do lewego widoku zniknie wraz z widokiem, którego dotyczy, a Ty pozostaniesz z ograniczeniem o wysokim priorytecie, że etykiety będą oddalone o 10 punktów od ich podglądu. Przy następnym przejściu do układu powinno to spowodować ich rozszerzenie w lewo, dopóki nie wypełnią szerokości podglądu, ale w celu uzyskania odstępów wokół krawędzi.
Jedno ważne zastrzeżenie: jeśli kiedykolwiek chcesz przywrócić lewy widok na obrazie, musisz nie tylko dodać go z powrotem do hierarchii widoków, ale także przywrócić wszystkie jego ograniczenia w tym samym czasie. Oznacza to, że potrzebujesz sposobu na przywrócenie 10-punktowego ograniczenia odległości między widokiem i jego etykietami, ilekroć ten widok zostanie ponownie wyświetlony.
źródło
|-(space)-[hidden(0)]-(space)-[visible]
jest efektywny|-(2*space)-[visible]
. Po drugie, widok ten może zacząć rzucać naruszenia ograniczeń w zależności od własnego poddrzewa i ograniczeń widoku - nie możesz zagwarantować, że możesz dowolnie ograniczyć widok o szerokości 0 i sprawić, by nadal działał.|-[otherViews]-[eitherThis][orThis]-|
:), ale w końcu napotkałem ten problem.Dodawanie lub usuwanie ograniczeń w czasie wykonywania jest operacją ciężką, która może wpływać na wydajność. Istnieje jednak prostsza alternatywa.
Dla widoku, który chcesz ukryć, ustaw ograniczenie szerokości. Ogranicz inne widoki z wiodącą poziomą przerwą do tego widoku.
Aby ukryć, zaktualizuj
.constant
ograniczenie szerokości do 0.f. Pozostałe widoki zostaną automatycznie przesunięte w lewo, aby przyjąć pozycję.Zobacz moją inną odpowiedź tutaj, aby uzyskać więcej informacji:
Jak zmienić ograniczenia etykiety podczas działania?
źródło
Dla tych, którzy wspierają iOS 8+ tylko, jest to nowy obiekt Boolean aktywny . Pomoże to dynamicznie włączać tylko potrzebne ograniczenia
Gniazdo PS Constraint musi być mocne , a nie słabe
Przykład:
Ponadto, aby naprawić błąd w serii ujęć, musisz odznaczyć
Installed
pole wyboru dla jednego z tych ograniczeń.UIStackView (iOS 9+)
Jeszcze jedną opcją jest zawinięcie swoich widoków
UIStackView
. Po ukryciu widokuUIStackView
automatycznie zaktualizuje układźródło
UIStackView
automatyczniehidden
zmienia swoje widoki, gdy właściwość jest zmieniana w dowolnym z jego widoków podrzędnych (iOS 9+).Przejdź do 11:48 w tym wideo WWDC, aby zobaczyć demo:
Tajemnice automatycznego układu, część 1
źródło
Mój projekt używa niestandardowej
@IBDesignable
podklasyUILabel
(aby zapewnić spójność kolorów, czcionek, wypustek itp.) I zaimplementowałem coś takiego:Dzięki temu podklasa etykiet może brać udział w automatycznym układzie, ale nie zajmuje miejsca, gdy jest ukryta.
źródło
Dla Googlersów: na odpowiedzi Maxa, aby rozwiązać problem dopełniania, który wielu zauważyło, po prostu zwiększyłem wysokość etykiety i użyłem tej wysokości jako separatora zamiast rzeczywistego wypełnienia. Ten pomysł można rozszerzyć na dowolny scenariusz z widokami zawierającymi.
Oto prosty przykład:
W takim przypadku odwzorowuję wysokość etykiety autora na odpowiednią
IBOutlet
:a kiedy ustawię wysokość ograniczenia na
0.0f
, zachowujemy „wypełnienie”, ponieważ pozwala na to wysokość przycisku Play .źródło
NSLayoutConstraint
wierzę, że chcesz zaktualizowaćconstant
właściwość twoichauthorLabelHeight
.połącz ograniczenie między uiview a etykietami jako IBOutlet i ustaw element członkowski priorytet na mniejszą wartość, gdy ustawiony ukryty = TAK
źródło
Skończyło się na stworzeniu 2 xibów. Jeden z lewym widokiem, a drugi bez niego. Zarejestrowałem się zarówno w kontrolerze, a następnie zdecydowałem, którego użyć podczas cellForRowAtIndexPath.
Używają tej samej klasy UITableViewCell. Minusem jest to, że istnieje pewna duplikacja zawartości między xib, ale te komórki są dość podstawowe. Plusem jest to, że nie mam dużo kodu do ręcznego zarządzania usuwaniem widoku, aktualizowaniem ograniczeń itp.
Ogólnie rzecz biorąc, jest to prawdopodobnie lepsze rozwiązanie, ponieważ są to technicznie różne układy i dlatego powinny mieć różne xib.
źródło
W takim przypadku odwzorowuję wysokość etykiety autora na odpowiedni IBOutlet:
a kiedy ustawię wysokość ograniczenia na 0.0f, zachowujemy „padding”, ponieważ pozwala na to wysokość przycisku Play.
źródło
Użyj dwóch UIStackView poziomego i pionowego, gdy ukryty jest widok częściowy stosu, inne widoki częściowe stosu zostaną przeniesione, użyj opcji Dystrybucja -> Wypełnij proporcjonalnie do stosu pionowego dwoma etykietami UIL i należy ustawić ograniczenia szerokości i wysokości dla pierwszego UIView
źródło
Spróbuj, zaimplementowałem poniższy kod,
Mam jeden widok na ViewController w dodanych trzech innych widokach. Gdy jakikolwiek widok jest ukryty, pozostałe dwa zostaną przeniesione, wykonaj poniższe kroki. ,
1. plikViewController.h
2.ViewController.m
Mam nadzieję, że ta logika komuś pomoże.
źródło
W moim przypadku ustawiłem stałą ograniczenia wysokości na,
0.0f
a także ustawiłemhidden
właściwość naYES
.Aby ponownie wyświetlić widok (z widokami podrzędnymi), zrobiłem coś przeciwnego: ustawiłem stałą wysokości na wartość niezerową i ustawiłem
hidden
właściwość naNO
.źródło
Użyję poziomego widoku stosu. Może usunąć ramkę, gdy widok podrzędny jest ukryty.
Na poniższym obrazku czerwony widok jest faktycznym kontenerem dla twojej zawartości i ma 10pt końcowe miejsce na pomarańczowy superview (ShowHideView), a następnie po prostu podłącz ShowHideView do IBOutlet i pokaż / ukryj / usuń programowo.
źródło
To moje kolejne rozwiązanie wykorzystujące ograniczenie pierwszeństwa. Ideą jest ustawienie szerokości na 0.
utwórz widok kontenera (pomarańczowy) i ustaw szerokość.
utwórz widok zawartości (czerwony) i ustaw odstęp 10pt na podgląd (pomarańczowy). Zwróć uwagę na końcowe ograniczenia miejsca, istnieją 2 końcowe ograniczenia o różnym priorytecie. Niski (= 10) i wysoki (<= 10). Jest to ważne, aby uniknąć dwuznaczności.
Ustaw szerokość widoku pomarańczowego na 0, aby ukryć widok.
źródło
Jak sugeruje no_scene, zdecydowanie możesz to zrobić, zmieniając priorytet ograniczenia w czasie wykonywania. Było to dla mnie znacznie łatwiejsze, ponieważ miałem więcej niż jeden widok blokujący, który należałoby usunąć.
Oto fragment kodu przy użyciu ReactiveCocoa:
źródło
Na wypadek, gdyby to komuś pomogło, zbudowałem klasę pomocniczą do używania formatu wizualnego ograniczeń . Używam go w mojej bieżącej aplikacji.
AutolayoutHelper
Może być nieco dostosowany do moich potrzeb, ale może okazać się przydatny lub możesz go zmodyfikować i stworzyć własnego pomocnika.
Muszę podziękować Timowi za jego odpowiedź powyżej , tę odpowiedź na temat UIScrollView, a także ten samouczek .
źródło
Oto jak ponownie wyrównaj moje uiviews, aby uzyskać twoje rozwiązanie:
Stworzyłem własną zasadę kciuka. Ilekroć musisz ukryć / pokazać dowolny podgląd uiview, na którego ograniczenia może mieć wpływ, dodaj wszystkie dotknięte / zależne widoki podrzędne w uiview i aktualizuj jego stałe ograniczenie wiodące / końcowe / górne / dolne.
źródło
To stare pytanie, ale wciąż mam nadzieję, że to pomoże. Pochodzący z Androida, na tej platformie masz przydatną metodę
isVisible
ukrywania go przed widokiem, ale nie bierzesz także pod uwagę ramki, gdy autoukład rysuje widok.Używając rozszerzenia i rozszerzenia „uiview”, możesz wykonać podobną funkcję w systemie iOS (nie jestem pewien, dlaczego nie ma go już w UIKit) tutaj implementacja w swift 3:
źródło
właściwym sposobem na to jest wyłączenie ograniczeń za pomocą isActive = false. zauważ jednak, że dezaktywacja ograniczenia usuwa je i zwalnia, więc musisz mieć dla nich mocne gniazda.
źródło
Najłatwiejszym rozwiązaniem jest użycie UIStackView (poziomo). Dodaj do widoku stosu: pierwszy widok i drugi widok z etykietami. Następnie ustaw właściwość isHidden pierwszego widoku na false. Wszystkie ograniczenia zostaną obliczone i zaktualizowane automatycznie.
źródło
Myślę, że to najprostsza odpowiedź. Sprawdź, czy to działa:
sprawdź tutaj https://www.youtube.com/watch?v=EBulMWMoFuw
źródło