2013-09-25 20 views
33

Ich habe Probleme mit Auto-Layout auf einem xcode 5 Projekt. Ich verwende einen Plain View Controller mit einem Navigationscontroller. Ich habe eine MKMapView auf der oberen Hälfte und eine UITableView auf der unteren Hälfte. Ich verwende storyboards und habe den Prototyp UITableViewCell konfiguriert, aber ich füge die Einschränkungen durch Code hinzu. Ich habe jede Kontrolle im Prototyp überprüft und sehe keine dort konfigurierten Einschränkungen. Mein Problem tritt auf, wenn ich die Einschränkungen für die UITableViewCell hinzufügen. Ich habe den folgenden Code in den Zellen:Problem mit AutoLayout auf 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]]; 
} 

Ich bekomme Folgendes in der Debugging-Konsole. Die Ausnahme wird durch die erste addConstraints-Zeile ausgelöst. Wenn ich nur durch diejenigen, weiterhin dann schließlich alles zeigt sich, wie es sein sollte, wie es aussieht wie Xcode ist die Wahl der richtigen Zwang zu brechen:

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. 

Die dritte NSIBPrototypingLayoutConstraint zeigt 78 Punkte zwischen dem Rand der Ansicht und eine Etikette. Dort ist der Prototyp grob positioniert (und wenn ich ihn in den Prototyp verschiebe, sehe ich die Änderung in der Constraint in der Debugging-Konsole), aber das widerspricht meiner eigenen Einschränkung des "Standard" -Distanzes zwischen der Bildansicht und dem Label .

Ich habe versucht, die translatesAutoresizingMaskIntoConstraints=NO in der Ansicht Controller cellForRowAtIndexPath zu setzen, aber das scheint auch nicht zu helfen. Wie kann ich das Layout reparieren?

+0

Ich bemerkte einen off-by-one Fehler in iOS7, der ein ähnliches Problem verursachte. Ich habe alle Beschränkungen in IB spezifiziert und XCode war glücklich. Aber die Summe aller vertikalen Größen in der Ausnahme Matt

Antwort

78

Ein paar Dinge hier decken:

  1. Die NSIBPrototypingLayoutConstraint Zwänge, die Sie in laufen lassen (und die verursachen Ausnahmen) sind automatisch generiert durch Interface Builder, um Ihre Storyboard oder XIB Ansicht zu machen Layout nicht eindeutig. Es ist ziemlich hinterhältig, dies zu tun, aber es fügt automatisch die minimalen Einschränkungen hinzu, die erforderlich sind, damit die Position und Größe jeder mehrdeutigen Ansicht vollständig spezifiziert wird. Dies ist eine Änderung gegenüber Xcode 4, da Sie in Xcode 4 keine mehrdeutigen Layouts in Interface Builder haben konnten. Mit Xcode 5 und höher können Sie jedoch, IB wird diese Einschränkungen für Sie automatisch generieren, wenn Ihr Layout zur Kompilierungszeit mehrdeutig ist.

    Um dieses Problem zu beheben, fügen Sie in Interface Builder die minimal erforderlichen Einschränkungen hinzu, sodass die Position der einzelnen Ansichten & vollständig angegeben wird. Wählen Sie dann jede dieser unerwünschten Integritätsbedingungen aus, wechseln Sie zum rechten Seitenleisten-Inspektor und aktivieren Sie die Option Box neben Placeholder - Entfernen zur Erstellungszeit.

    Screenshot of the constraint Placeholder checkbox in Xcode 6.

    Nicht nur, dass dieses Kontrollkästchen entfernt die Einschränkung Sie hinzugefügt, aber am wichtigsten ist es, die automatisch generierte IB Einschränkung von an ihre Stelle verhindern! (Wie Sie sich vorstellen können, ist dies ziemlich mühsam, wenn Sie mehrere Ansichten in IB haben und alle Ihre Einschränkungen im Code verwalten möchten. Aus diesem Grund sollten Sie vermeiden, IB vollständig für Ansichtshierarchien zu verwenden, in denen Sie Auto implementieren möchten Layout programmgesteuert.)

    Was ist der Unterschied zwischen einer Platzhaltereinschränkung und einer nicht deinstallierten Einschränkung? Hier ist eine Folie aus meiner Adaptive Auto Layout talk (video) (PDF slides) Vergleich der beiden:

    Comparison between Placeholder constraints and Uninstalled constraints.

  2. In updateConstraints, Sie nicht wollen, Einschränkungen entfernen und erneut fügen Sie sie wie Sie es haben. Warum nicht?Im Wesentlichen ist es für die Leistung schrecklich, und ich habe mit Apple-Ingenieuren bestätigt, dass dies keine gute Idee ist. Weitere Details finden Sie unter question/answer I have posted here sowie unter answer. Um zu verhindern, dass Constraints mehrmals hinzugefügt werden, verwenden Sie ein boolesches Flag (z. B. hasSetupConstraints), das Sie auf YES setzen, sobald Sie Ihre Constraints das erste Mal eingerichtet haben. Wenn updateConstraints erneut aufgerufen wird, können Sie sofort zurückkehren, wenn Sie keine haben Neue Einschränkungen zum Hinzufügen Weitere Informationen finden Sie unter this question.

  3. Der Code zum Entfernen von Einschränkungen funktioniert möglicherweise nicht vollständig. Dies liegt daran, dass [view removeConstraints:view.constraints] nur die Einschränkungen entfernt, die zu view hinzugefügt wurden - denken Sie daran, dass Einschränkungen zu jeder allgemeinen Übersicht der Ansichten hinzugefügt werden können, die sie beschränken - und die zu view hinzugefügten Einschränkungen möglicherweise nicht die einzigen sind, die das Layout von view beeinflussen ! Wenn Sie eine Reihe von Integritätsbedingungen entfernen müssen, sollten Sie eine Referenz auf jede dieser Integritätsbedingungen in einer Eigenschaft speichern (z. B. eine NSArray-Eigenschaft, die NSLayoutConstraint-Instanzen enthält) und anschließend diese Integritätsbedingungen mithilfe der API NSLayoutConstraint oder the PureLayout open-source library deaktivieren/entfernen. Sie sollten nur so wenige Einschränkungen wie möglich deaktivieren/entfernen, da dies rechenintensiv ist. Andererseits ist das Ändern der constant einer beliebigen Einschränkung sehr effizient und empfehlenswert, und Sie müssen die Einschränkung nicht entfernen oder neu hinzufügen, um dies zu tun.

+0

Vielen Dank für Ihre Hilfe. Ich habe die Einschränkungen in IB hinzugefügt, sie als Platzhalter markiert und die Ausnahme vermieden. Wenn ich den Rest Ihres Rates durchdenke, denke ich, dass es nicht wirklich viele Gründe gibt, warum ich nicht alle diese Einschränkungen in IB spezifizieren und den Code vollständig entfernen kann. Dies ist mein erstes Projekt mit Autolayout, und auf dem View-Controller musste ich Constraints bei Rotation hinzufügen/entfernen, also versuchte ich im Prinzip, den gleichen Ansatz für die Tabellenansichtszelle zu verwenden. Aber wie du gesagt hast, muss ich nicht. Danke noch einmal! –

+0

Kein Problem. Wenn Sie die Einschränkungen gut von IB bekommen können, gehen Sie dafür. Aber ich persönlich habe grundsätzlich aufgehört, IB zu benutzen, besonders wenn es um Auto-Layout geht. IB ist täuschend einfach anzusehen, kann aber so viel Schmerz verursachen, außer für die einfachsten Sichteinstellungen (oft ist das, was du siehst, ** nicht ** was du bekommst!). Wie auch immer ... frag ruhig, ob du über irgendwelche anderen Stolpersteine ​​stolperst. – smileyborg

+0

Ich verstehe nicht, was Sie meinen "Nicht nur, dass dieses Kontrollkästchen die von Ihnen hinzugefügte Einschränkung entfernt". Warum möchten Sie eine Beschränkung entfernen, die Sie gerade hinzugefügt haben? – drc

Verwandte Themen