webentwicklung-frage-antwort-db.com.de

Gibt es eine Möglichkeit, eine Beschränkung zwischen einer Ansicht und der obersten Layout-Anleitung in einer Xib-Datei hinzuzufügen?

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.

enter image description here

Wenn ich jedoch dieselbe Operation in einer Xib-Datei mache, verschwindet diese Option.

enter image description here

Gibt es eine Möglichkeit, diese Art von Einschränkungen in Xib-Dateien einzufügen? Oder muss ich sie mit Code hinzufügen?

73
Henry H Miao

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]
];
77
Neeraj Khede

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 :)

14
ananfang

Ab iOS 9 können Sie dies auch mit topLayoutGuides anchors einfacher machen:

  • Schnell 3

view.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive = true

  • ObjC

[controller.view.topAnchor constraintEqualToAnchor:controller.topLayoutGuide.bottomAnchor].active = YES;

9
Radu Vlad

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 ];
6

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.

6
Cao Huu Loc

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.

5
David Pettigrew

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)
            }
        }
    }
}
0
f3dm76