In iOS 7 können wir nun eine Einschränkung zwischen einer Ansicht und der obersten Layout-Anleitung hinzufügen. Dies ist meines Erachtens sehr nützlich, um das Problem der Statusleistenversetzung in iOS7 zu lösen (insbesondere, wenn in der Ansicht keine Navigationsleiste angezeigt wird).
In einer Storyboard-Datei kann ich diese Art von Einschränkungen problemlos hinzufügen. Halten Sie einfach die Steuertaste gedrückt, und ziehen Sie die Ansicht in den Container. Die Option "Top Space to Top Layout Guide" wird angezeigt.
Wenn ich jedoch dieselbe Operation in einer Xib-Datei mache, verschwindet diese Option.
Gibt es eine Möglichkeit, diese Art von Einschränkungen in Xib-Dateien einzufügen? Oder muss ich sie mit Code hinzufügen?
Sie sollten sich auf das folgende Beispiel beziehen, das wird Ihnen definitiv bei Ihrem Problem helfen. Ich habe dies von http://developer.Apple.com .
[button setTranslatesAutoresizingMaskIntoConstraints: NO];
id topGuide = myViewController.topLayoutGuide;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings (button, topGuide);
[myViewController.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat: @"V:[topGuide]-20-[button]"
options: 0
metrics: nil
views: viewsDictionary]
];
Hier ist meine alternative Lösung.
Suchen Sie einen UIView als Drehpunkt, legen Sie für die obere Layoutbedingung einen festen vertikalen Abstand an der Oberseite des Containers fest.
Ziehen Sie diese Layout-Einschränkung als IBOutlet, z. B.
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;
Zum Schluss einfach die viewWillLayoutSubviews-Methode von UIViewController wie folgt überschreiben
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.topLayoutConstraint.constant = [self.topLayoutGuide length] + YOUR_TOP_CONSTRSINT;
}
Alle Top-Constraints der anderen Ansichten basieren auf dieser Pivot-Ansicht, alles erledigt :)
Ab iOS 9 können Sie dies auch mit topLayoutGuides anchors
einfacher machen:
view.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive = true
[controller.view.topAnchor constraintEqualToAnchor:controller.topLayoutGuide.bottomAnchor].active = YES;
Natürlich können Sie die Einschränkung zwischen einer Ansicht und dem top layout guide
oder bottom layout guide
nicht nur programmgesteuert hinzufügen, sondern Sie können auch die Einschränkung zwischen einer Ansicht und dem top and bottom layout guide
mithilfe von KVConstraintExtensionsMaster library entfernen und darauf zugreifen.
// create containerView
UIView *containerView = [UIView prepareNewViewForAutoLayout];
[containerView setBackgroundColor:[UIColor brownColor]];
[self.view addSubview:containerView];
// To add Top and Bottom Layout Guide constraint of containerView
[self applyTopLayoutGuideConstraintToView:containerView withPadding:0];
[self applyBottomLayoutGuideConstraintToView:containerView withPadding:50];
// To access top Layout Guide Constraint and update it's constant value.
NSLayoutConstraint *topLayoutGuideConstraint = [self accessAppliedTopLayoutGuideConstraintFromView:containerView];
topLayoutGuideConstraint.constant = 50;
// To access bottom Layout Guide Constraint and update it's constant value with animation
NSLayoutConstraint *bottomLayoutGuideConstraint = [self accessAppliedBottomLayoutGuideConstraintFromView:containerView];
bottomLayoutGuideConstraint.constant = 80;
[self.view updateModifyConstraintsWithAnimation:NULL]; // call this for animation
// To remove Top and Bottom Layout Guide constraint of containerView
[self removeAppliedTopLayoutGuideConstraintFromView:containerView];
[self removeAppliedBottomLayoutGuideConstraintFromView:containerView ];
Selbst mit XCode 6 kann ich bisher keine Steuerelemente an der obersten Layout-Anleitung für .xib-Dateien ausrichten. Stattdessen verwende ich einen alternativen Weg.
Zuerst stelle ich beim Interface Builder immer noch Steuerelemente am oberen Rand der Ansicht des Viewcontrolers aus.
In der viewDidLoad-Methode ersetze ich dann einige Einschränkungen, damit sie an der oberen Layout-Anleitung statt an der Hauptansicht ausgerichtet werden:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *constraints = self.view.constraints;
for (NSLayoutConstraint *constraint in constraints) {
if ( (constraint.firstItem == self.view) && (constraint.firstAttribute == NSLayoutAttributeTop) ) {
NSLayoutConstraint *newConstraint = [self constraint:constraint replaceFirstItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom];
[self.view removeConstraint:constraint];
[self.view addConstraint:newConstraint];
} else if ( (constraint.secondItem == self.view) && (constraint.secondAttribute == NSLayoutAttributeTop) ) {
NSLayoutConstraint *newConstraint = [self constraint:constraint replaceSecondItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom];
[self.view removeConstraint:constraint];
[self.view addConstraint:newConstraint];
}
}
}
- (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceFirstItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute {
UILayoutPriority priority = constraint.priority;
NSLayoutRelation relation = constraint.relation;
id secondItem = constraint.secondItem;
NSLayoutAttribute secondAttribute = constraint.secondAttribute;
CGFloat multiplier = constraint.multiplier;
CGFloat constant = constraint.constant;
NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:newItem attribute:newAttribute relatedBy:relation toItem:secondItem attribute:secondAttribute multiplier:multiplier constant:constant];
newConstraint.priority = priority;
return newConstraint;
}
- (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceSecondItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute {
UILayoutPriority priority = constraint.priority;
id firstItem = constraint.firstItem;
NSLayoutAttribute firstAttribute = constraint.firstAttribute;
NSLayoutRelation relation = constraint.relation;
CGFloat multiplier = constraint.multiplier;
CGFloat constant = constraint.constant;
NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:firstItem attribute:firstAttribute relatedBy:relation toItem:newItem attribute:newAttribute multiplier:multiplier constant:constant];
newConstraint.priority = priority;
return newConstraint;
}
Ich denke, das ist nicht der beste Weg, weil wir Objekte ersetzen, die wir im Interface Builder definieren. Es kann jedoch eine alternative Möglichkeit sein, über die wir nachdenken können.
Ich denke, der Grund, warum sie nicht im XIB erscheinen, ist, dass in dieser Situation keine Kenntnis der Ansichtssteuerungshierarchie vorhanden ist. In einem Storyboard kann IB jedoch erkennen, wo sich die Hilfslinien aus der Ansichtssteuerungshierarchie befinden, in der sich die Ansicht befindet. Dh Wenn es in einem UINavigationController enthalten ist, kann es feststellen, dass sich die oberste Layouthilfe unterhalb der Navigationssymbolleiste befindet.
Cao Huu Locs Antwort mit Swift 4
extension NSLayoutConstraint {
func constraintReplacing(firstItemWith newFirstItem: UILayoutSupport, withAttribute newFirstAttribute: NSLayoutAttribute) -> NSLayoutConstraint {
return NSLayoutConstraint(item: newFirstItem, attribute: newFirstAttribute, relatedBy: relation, toItem: secondItem, attribute: secondAttribute, multiplier: multiplier, constant: constant)
}
func constraintReplacing(secondItemWith newSecondItem: UILayoutSupport, withAttribute newSecondAttribute: NSLayoutAttribute) -> NSLayoutConstraint {
return NSLayoutConstraint(item: firstItem as Any, attribute: firstAttribute, relatedBy: relation, toItem: newSecondItem, attribute: newSecondAttribute, multiplier: multiplier, constant: constant)
}
}
class YourViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
for constraint in view.constraints {
if constraint.firstItem === view && constraint.firstAttribute == .top {
let newConstraint = constraint.constraintReplacing(firstItemWith: topLayoutGuide, withAttribute: .bottom)
view.removeConstraint(constraint)
view.addConstraint(newConstraint)
}
if constraint.secondItem === view && constraint.secondAttribute == .top {
let newConstraint = constraint.constraintReplacing(secondItemWith: topLayoutGuide, withAttribute: .bottom)
view.removeConstraint(constraint)
view.addConstraint(newConstraint)
}
}
}
}