2013-09-25 19 views
33

Mam problem z autolayout w projekcie xcode 5. Używam zwykłego kontrolera widoku w środku za pomocą kontrolera nawigacyjnego. Mam MKMapView w górnej połowie i UITableView w dolnej połowie. Używam storyboards i skonfigurowałem prototyp UITableViewCell, ale dodam ograniczenia za pomocą kodu. Podwójnie sprawdziłem każdą kontrolę w prototypie i nie widzę tam żadnych ograniczeń. Mój problem występuje, gdy dodam ograniczenia dla UITableViewCell. Mam następujący kod w komórkach:Problemy z AutoLayout na UITableViewCell

-(void)updateConstraints { 
    [super updateConstraints]; 
    //first remove old constraints 
    [self removeConstraints:self.constraints]; 
    [self.nameLabel removeConstraints:self.nameLabel.constraints]; 
    [self.addressLabel removeConstraints:self.nameLabel.constraints]; 
    [self.rentableSquareFeetLabel removeConstraints:self.rentableSquareFeetLabel.constraints]; 
    [self.lastSaleAmountLabel removeConstraints:self.lastSaleAmountLabel.constraints]; 
    [self.lastSaleDateLabel removeConstraints:self.lastSaleAmountLabel.constraints]; 
    [self.thumbnailImageView removeConstraints:self.thumbnailImageView.constraints]; 

    //then set up constraints 
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_thumbnailImageView, _nameLabel, _rentableSquareFeetLabel, _lastSaleAmountLabel, _addressLabel, _lastSaleDateLabel); 
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_thumbnailImageView(60)]-[_nameLabel(<=200)]-(>=8)-[_rentableSquareFeetLabel]-(>=8)-[_lastSaleAmountLabel]|" options:0 metrics:nil views:viewsDictionary]]; 
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_nameLabel]-(-4)-[_addressLabel]" options:NSLayoutFormatAlignAllLeading metrics:nil views:viewsDictionary]]; 
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_lastSaleAmountLabel]-(-4)-[_lastSaleDateLabel]" options:NSLayoutFormatAlignAllLeading metrics:nil views:viewsDictionary]]; 
} 

Dostaję następujące w konsoli debugowania. Wyjątek jest wywoływany przez pierwszą linię addConstraints. Gdybym tylko kontynuować przez te następnie ostatecznie wszystko przedstawia się tak, jak powinno być, jak to wygląda Xcode wybiera się przełamać poprawnego ograniczenia:

2013-09-25 15:07:14.169 PECProperties[32381:a0b] 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) (
    "<NSIBPrototypingLayoutConstraint:0x9d56c70 'IB auto generated at build time for view with fixed frame' H:|-(0)-[UIImageView:0x9d558f0](LTR) (Names: '|':UITableViewCellContentView:0x9d55620)>", 
    "<NSIBPrototypingLayoutConstraint:0x9d56d20 'IB auto generated at build time for view with fixed frame' H:[UIImageView:0x9d558f0(60)]>", 
    "<NSIBPrototypingLayoutConstraint:0x9d56d80 'IB auto generated at build time for view with fixed frame' H:|-(78)-[UILabel:0x9d559e0](LTR) (Names: '|':UITableViewCellContentView:0x9d55620)>", 
    "<NSLayoutConstraint:0x9d53830 H:[UIImageView:0x9d558f0]-(NSSpace(8))-[UILabel:0x9d559e0]>") 

Will attempt to recover by breaking constraint <NSIBPrototypingLayoutConstraint:0x9d56d80 'IB auto generated at build time for view with fixed frame' H:|-(78)-[UILabel:0x9d559e0](LTR) (Names: '|':UITableViewCellContentView:0x9d55620)> 

Break on objc_exception_throw to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. 

Trzeci NSIBPrototypingLayoutConstraint pokazuje 78 punktów pomiędzy krawędzią widzenia oraz etykieta. Właśnie tam prototyp jest z grubsza pozycjonowany (i jeśli poruszę go w prototypie, widzę zmianę ograniczenia w konsoli debugowania), ale to jest w konflikcie z moim własnym ograniczeniem "standardowej" odległości między widokiem obrazu a etykietą .

Próbowałem ustawić translatesAutoresizingMaskIntoConstraints=NO w kontrolerze widoku cellForRowAtIndexPath, ale to też nie pomaga. Jak mogę naprawić układ?

+0

Zauważyłem błąd typu "jeden po drugim" w systemie iOS7, który spowodował podobny problem. Podawałem wszystkie ograniczenia w IB i XCode był szczęśliwy. Ale suma wszystkich pionowych rozmiarów w wyjątku Matt

Odpowiedz

78

Kilka rzeczy na pokrycie tutaj:

  1. The NSIBPrototypingLayoutConstraint ograniczenia, które używasz do (i które są przyczyną wyjątkami) są automatycznie generowane przez Interface Builder, aby uczynić Państwa Storyboard lub XIB widok układ niejednoznaczny. Jest to dość podstępne, ale automatycznie dodaje minimalne wymagane ograniczenia, aby pozycja i rozmiar każdego niejednoznacznego widoku stały się w pełni określone. Jest to zmiana z Xcode 4, ponieważ w Xcode 4 nie można mieć niejednoznacznych układów w Konstruktorze interfejsu. Z Xcode 5 i nowszymi możesz, jednak IB automatycznie wygeneruje te ograniczenia dla ciebie, jeśli twój układ jest niejednoznaczny w czasie kompilacji.

    Aby rozwiązać ten problem, należy dodać minimalne wymagane ograniczenia w Konstruktorze interfejsów, tak aby rozmiar każdego z miejsc został dokładnie określony, a następnie wybrać każde z tych niechcianych ograniczeń, przejść do prawego paska bocznego Inspektor atrybutów i sprawdzić pole obok: Symbol zastępczy - usuń w czasie kompilacji.

    Screenshot of the constraint Placeholder checkbox in Xcode 6.

    Nie tylko ta opcja usunąć ograniczenie dodaną, ale najważniejsze będzie to uniemożliwić automatycznie wygenerowane IB ograniczenie podejmowania swoje miejsce! (Jak możesz sobie wyobrazić, jest to dość uciążliwe, gdy masz wiele widoków w IB i chcesz zarządzać wszystkimi ograniczeniami w kodzie, dlatego możesz całkowicie uniknąć użycia IB do wyświetlania hierarchii, w których zamierzasz implementować Auto Układ programowy.)

    Jaka jest różnica między ograniczeniem zastępczym a ograniczeniem niezainstalowanym? Oto slajd z mojego Adaptive Auto Layout talk (video) (PDF slides) porównując dwa:

    Comparison between Placeholder constraints and Uninstalled constraints.

  2. W updateConstraints, nie chcesz, aby usunąć ograniczenia i ponownie dodać je jak tam masz. Dlaczego nie?Zasadniczo jest to fatalne z punktu widzenia wydajności, a inżynierowie Apple potwierdzili, że nie jest to dobry pomysł. Zobacz question/answer I have posted here po więcej szczegółów, a także answer. Aby zapobiec dodawaniu ograniczeń więcej niż raz, użyj flagi boolowskiej (np. hasSetupConstraints), którą ustawisz na TAK po pierwszym skonfigurowaniu wiązań, a jeśli zostanie ponownie wywołana updateConstraints, możesz po prostu natychmiast wrócić, jeśli nie masz nowe ograniczenia do dodania. Zobacz: this question w celu dalszej dyskusji.

  3. Kod, którego używasz do usunięcia wiązań, może nie działać w pełni. Dzieje się tak, ponieważ [view removeConstraints:view.constraints] usunie tylko ograniczenia, które zostały dodane do view - pamiętaj, że ograniczenia można dodawać do wszystkich popularnych widoków, które ograniczają - a ograniczenia dodane do view mogą nie być jedynymi, które wpływają na układ view ! Jeśli chcesz usunąć pewną liczbę ograniczeń, powinieneś zapisać odniesienie do każdego z tych ograniczeń w właściwości (np. Właściwość NSArray zawierająca instancje NSLayoutConstraint), a następnie dezaktywować/usunąć te ograniczenia za pomocą interfejsu API w NSLayoutConstraint lub the PureLayout open-source library. Powinieneś tylko dezaktywować/usunąć jak najmniej ograniczeń, ponieważ jest to kosztowne pod względem obliczeniowym. Z drugiej strony, zmiana constant jakiegokolwiek ograniczenia jest bardzo wydajna i zachęcająca i nie trzeba usuwać ani ponownie dodawać ograniczenia, aby to zrobić.

+0

Dziękuję bardzo za pomoc. Dodałem ograniczenia w IB, oznaczono je jako symbol zastępczy i uniknąłem wyjątku. Zastanawiając się nad resztą twoich porad, myślę, że nie ma naprawdę powodu, dla którego nie mogę określić wszystkich tych ograniczeń w IB i całkowicie usunąć kod. Jest to mój pierwszy projekt z autolayout, a na kontrolerze widoku potrzebowałem dodać/usunąć ograniczenia przy rotacji, więc zasadniczo próbowałem zastosować to samo podejście w komórce widoku tabeli. Ale jak zauważyłeś, nie muszę. Dzięki jeszcze raz! –

+0

Bez problemu. Jeśli uda ci się uzyskać ograniczenia działające dobrze od IB, idź do niego. Ale osobiście zasadniczo przestałem używać IB, szczególnie jeśli chodzi o Auto Layout. IB jest zwodniczo prosty, ale może wywoływać tak wiele bólu dla niczego poza najprostszymi ustawieniami widoku (często to, co widzisz, nie ** to, co dostajesz!). W każdym razie ... nie wahaj się zapytać, czy natkniesz się na inne przeszkody. – smileyborg

+0

Nie rozumiem, co masz na myśli przez "nie tylko to pole wyboru usuwa dodane ograniczenie" dlaczego chcesz usunąć właśnie dodane ograniczenie? – drc

Powiązane problemy