Czy mogę wyłączyć automatyczne układanie dla określonego widoku podrzędnego w czasie wykonywania?

104

Mam widok, który wymaga programowego manipulowania ramką - jest to rodzaj widoku dokumentu, który zawija się do zawartości, która jest następnie przewijana i powiększana wokół superwiewu poprzez manipulowanie początkiem ramki. Autolayout walczy z tym w czasie wykonywania.

Całkowite wyłączenie autoukładu wydaje się nieco trudne, ponieważ można go rozsądnie wykorzystać do obsługi układu dla innych widoków. Wygląda na to, że to, czego potrzebuję, to pewnego rodzaju „zerowe ograniczenie”.

terriblememory
źródło

Odpowiedzi:

168

Miałem ten sam problem. Ale rozwiązałem to.
Tak, możesz wyłączyć automatyczny układ w czasie wykonywania dla określonego UIView, zamiast wyłączać go dla całego xib lub storyboardu, który jest domyślnie ustawiony w Xcode 4.3 i nowszych.

Ustaw translatesAutoresizingMaskIntoConstraintsna YES, zanim ustawisz ramkę widoku podrzędnego:

self.exampleView.translatesAutoresizingMaskIntoConstraints = YES;
self.exampleView.frame = CGRectMake(20, 20, 50, 50);
Muhammad Aamir Ali
źródło
2
Wygląda to na przesadę w niektórych bardziej skomplikowanych przypadkach z wieloma widokami. W przypadku czegoś tak prostego jak to jest w porządku.
esh
@MuhammadAamirALi usunąć podwidok, a następnie dodać go z powrotem, może obniżyć wydajność. Czy możemy zarchiwizować lepsze rozwiązanie?
Nhat Dinh
2
@DinhNhat wyjaśniłem odpowiedź. Usunięcie i ponowne dodanie widoku podrzędnego nie jest konieczne.
Leandros
5
Pokazuje mi ostrzeżenie: „Nie można jednocześnie spełnić ograniczeń”.
NSPratik
1
Uratowałeś mi dzień ... tłumaczyAutoresizingMaskIntoConstraints ... kto wymyśla takie nieruchomości jak ta trzęsąca się głowa
Tintenklecks
50

Miałem podobny problem, w którym Autolayout przesłaniał niektóre z moich ustawień klatek w czasie wykonywania (miałem dynamiczny widok, który w niektórych przypadkach pchnął nowy kontroler widoku ... naciśnięcie, a następnie naciśnięcie przycisku Wstecz zresetowało widok początkowy).

Poradziłem sobie z tym, umieszczając mój kod manipulacji w viewDidLayoutSubviewsmoim kontrolerze widoku. Wydaje się, że jest to wywoływane po wywołaniu dowolnego ograniczenia mojo, ale przed viewDidAppear, więc użytkownik nie jest mądrzejszy.

jmstone617
źródło
1
Nie działa w przypadku self.navigationItem.titleView. Nadal nie szanuje zmiany kadru.
Henrik Erlandsson,
1
Jeśli próbujesz pomieszać ramkę widoku tytułowego, umieściłbym ją w widoku kontenera i dodałbym widok kontenera jako niestandardowy widok navigationItem.
jmstone617
2
U mnie też to zadziałało. Zmarnowałem 2h: 22m uderzając głową w przysłowiową ścianę, zanim odkryłem to obejście.
TMc
Dzięki. Już drugiego dnia zmagam się z tym problemem i teraz to działa!
apostolov
28

Być może po prostu ustawienie translatesAutoresizingMaskIntoConstraintsna YES(a nie dodanie dodatkowych ograniczeń mających wpływ na ten pogląd) pozwoli Ci ustawić ramkę bez walki system układu automatycznego.

Jon Hull
źródło
17

W iOS 8 możesz ustawić NSLayoutConstraint na aktywny lub nie. Więc jeśli używam kreatora interfejsów, dodaję wszystkie moje ograniczenia do OutletCollection, a następnie aktywuję lub dezaktywuję za pomocą:

NSLayoutConstraint.deactivateConstraints(self.landscapeConstraintsPad)
NSLayoutConstraint.activateConstraints(self.portraitConstraintsPad)

Konkretna aplikacja, do której go tutaj używam, ma różne ograniczenia w trybie pionowym i poziomym i aktywuję / dezaktywuję na podstawie obrotu urządzenia. Oznacza to, że mogę tworzyć skomplikowane zmiany układu w kreatorze interfejsu dla obu orientacji i nadal używać automatycznego układu bez szczegółowego kodu automatycznego układu.

Lub możesz aktywować / dezaktywować za pomocą removeConstraints i addConstraints.

bandejapaisa
źródło
Przepraszam za porwanie tak starego pytania, ale czy mogę zapytać, jak w pierwszej kolejności udało ci się dodać ograniczenia układu dla różnych układów? Nie mogę znaleźć opcji w narzędziu do tworzenia interfejsu, aby włączyć / wyłączyć ograniczenia. A może po prostu dodałeś ograniczenia dla obu układów i po prostu zignorowałeś twórcę interfejsu narzekającego na nieprawidłowe (nadpisujące) ograniczenia?
Malte
Cóż, możesz to zrobić, używając klas wielkości: developer.apple.com/library/ios/recipes/… , ale nie mogłem tego zrobić w ten sposób, ponieważ również wspierałem iOS 7, a klasy wielkości nie w pełni obsługują iOS 7 Zrobiłem to, obniżając priorytet sprzecznego ograniczenia. Nie jest to idealne rozwiązanie, ale zapobiega ostrzeżeniu. Myślę, że tak to zrobiłem ...
bandejapaisa
9

Nie wiem, czy to pomoże komukolwiek innemu, ale napisałem kategorię, aby było to wygodne, ponieważ często to robię.

UIView + DisableAutolayoutTemporently.h

#import <UIKit/UIKit.h>

@interface UIView (DisableAutolayoutTemporarily)

// the view as a parameter is a convenience so we don't have to always
// guard against strong-reference cycles
- (void)resizeWithBlock:(void (^)(UIView *view))block;

@end

UIView + DisableAutolayoutTemporently.m

#import "UIView+DisableAutoResizeTemporarily.h"
@implementation UIView (DisableAutoResizeTemporarily)

- (void)resizeWithBlock:(void (^)(UIView * view))block
{
    UIView *superview = self.superview;
    [self removeFromSuperview];
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    __weak UIView *weakSelf = self;
    block(weakSelf);
    [superview addSubview:self];
}

@end

Używam tego w ten sposób:

[cell.argumentLabel resizeWithBlock:^(UIView *view) {
    [view setFrame:frame];
}];

Mam nadzieję, że to pomoże.

michaelsnowden
źródło
Znakomity ! Użyłem zmodyfikowanej wersji twojego kodu do napisania prostej funkcji "hideControl" dla dowolnego UIView. Zasadniczo ustawia wysokość UIView na 0, ale, co najważniejsze, używa Twojego kodu, aby AutoLayout obsługiwał go poprawnie (w przeciwieństwie do użycia „someView.hidden = TRUE”). Tak więc elementy sterujące, które pojawiły się pod ukrytą kontrolką i miały połączone z nią odstępy w pionie, przesuwały się teraz w górę na ekranie, aby wypełnić lukę, w której wcześniej pojawił się ukryty widok.
Mike Gledhill
6

Możesz ustawić translatesAutoresizingMaskIntoConstraintstyp Boolean, wartość tak w zdefiniowanych przez użytkownika atrybutach środowiska wykonawczego UIView, które chcesz w xib / storyboard.

renaun
źródło
2
  • Otwórz projekt w 4.5
  • Wybierz scenorys
  • Otwórz inspektora plików
  • W dokumencie Interface Builder usuń zaznaczenie opcji „Użyj automatycznego układu”

Możesz podzielić wiele scenorysów, jeśli chcesz użyć autoukładu dla niektórych widoków.

Mike Bobbitt
źródło
10
To wyłącza automatyczne układanie dla całego storyboardu / stalówki. To, czego szukałem, to sposób (najlepiej programowy) na to, aby określone podglądy w ramach storyboardu / stalówki nie używały autoukładu, pozostawiając resztę robiącą to, co określono w scenorysie / końcówce.
terriblememory
Możesz użyć wielu scenorysów i po prostu wywołać te z / bez autolayout w razie potrzeby: // Zainicjuj kontroler widoku tablicy i szczegółów dla wyświetlania UIStoryboard * sb = [UIStoryboard storyboardWithName: @ "Storyboard" bundle: [NSBundle mainBundle]]; DetailViewController * dvController = [sb instantiateViewControllerWithIdentifier: entry.viewName];
Mike Bobbitt
1

U mnie działało programowe utworzenie widoku podrzędnego, w moim przypadku układ automatyczny mylił się z widokiem, który musiałem obracać wokół jego środka, ale kiedy utworzyłem ten widok programowo, zadziałał.

Andrespch
źródło
1

Moim zdaniem miałem etykietę i tekst. Etykieta miała gest przesuwania. Etykieta porusza się dobrze podczas przeciągania. Ale kiedy używam klawiatury w polu tekstowym, etykieta resetuje swoje położenie do pierwotnej lokalizacji zdefiniowanej w automatycznym układzie. Problem został rozwiązany, gdy szybko dodałem następujący element do etykiety. Dodałem to w viewWillAppear, ale można to dodać prawie wszędzie, gdzie masz dostęp do pola docelowego.

self.captionUILabel.translatesAutoresizingMaskIntoConstraints = true
Duże D
źródło
0

Zdarzyło mi się to w projekcie bez scenorysów lub plików xib. Cały kod 100%. Miałem baner reklamowy na dole i chciałem, aby granice widoku zatrzymały się na banerze reklamowym. Widok zmieniłby się automatycznie po załadowaniu. Wypróbowałem każdą rozdzielczość na tej stronie, ale żadna z nich nie działała.

Skończyło się na utworzeniu widoku podrzędnego ze skróconą wysokością i umieszczeniu go w głównym widoku kontrolera. Następnie cała moja zawartość trafiła do widoku podrzędnego. To bardzo łatwo rozwiązało problem, nie robiąc niczego, co wydawałoby się, że idzie pod prąd.

Myślę, że jeśli chcesz mieć widok, który nie jest normalnym rozmiarem, który wypełnia okno, powinieneś użyć do tego widoku podrzędnego.

RandallTo
źródło
0

Spotkałem się z podobnym scenariuszem, w którym dołączyłem do projektu, który został zainicjowany z automatycznym układem, ale musiałem wprowadzić dynamiczne poprawki w kilku widokach. Oto, co zadziałało dla mnie:

  1. NIE Miej widoków ani komponentów rozplanowanych w konstruktorze interfejsu.

  2. Dodaj swoje widoki czysto programowo, zaczynając od przydziału / inicjalizacji i odpowiedniego ustawienia ramek.

  3. Gotowe.

Tak.
źródło
0

Zamiast wyłączać automatyczne układanie, po prostu obliczyłbym nowe ograniczenie z ramką, którą zastępujesz. Wydaje mi się, że jest to właściwy sposób. Jeśli dostosowujesz komponenty, które opierają się na wiązaniach, dostosuj je odpowiednio.

Na przykład, jeśli masz ograniczenie w pionie wynoszące 0 między dwoma widokami (myView i otherView) i masz gest przesunięcia lub coś, co dostosowuje wysokość myView, możesz ponownie obliczyć ograniczenie za pomocą dostosowanych wartości.

self.verticalConstraint.constant = newMyViewYOriginValue - (self.otherView.frame.origin.y + self.otherView.frame.size.height);
[self.myView needsUpdateConstraints];
Myles Caley
źródło
0

Dla tych z Was, którzy używają automatycznego układu, sprawdź moje rozwiązanie tutaj . Powinieneś tworzyć @IBOutletograniczenia, które chcesz dostosować, a następnie zmieniać ich stałe.

Mikrofon
źródło
-16

jeśli jest to plik xib:

  1. wybierz plik .xib
  2. wybierz „Właściciela pliku”
  3. pokaż narzędzia
  4. kliknij: „File Inspector”
  5. W sekcji „Dokument kreatora interfejsów” wyłącz: „Użyj automatycznego układu”
Alish
źródło
1
Nie, to wyłącza automatyczne układanie dla całego xib. To, czego szukałem, to sposób na wyjęcie z systemu autoukładu tylko jednego podwidoku.
terriblememory