web-dev-qa-db-fra.com

Est-il possible d'ajouter une contrainte entre une vue et le guide de disposition supérieur dans un fichier xib?

Dans iOS 7, nous pouvons maintenant ajouter une contrainte entre une vue et le guide de présentation supérieur, ce qui me semble très utile pour résoudre le problème de décalage de la barre d'état dans iOS7 (surtout lorsqu'il n'y a pas de barre de navigation dans la vue).

Dans un fichier de storyboard, je peux facilement ajouter ce type de contraintes. Il vous suffit de maintenir la touche Ctrl enfoncée, puis de faire glisser la vue vers le conteneur. L’option "Guide de mise en page de haut en bas" apparaît.

enter image description here

Mais lorsque je fais la même opération dans un fichier xib, cette option disparaît.

enter image description here

Alors, est-il possible d'ajouter ce type de contrainte dans les fichiers xib? Ou dois-je les ajouter avec du code?

73
Henry H Miao

Vous devriez vous référer à l'exemple suivant, cela vous aidera certainement à résoudre votre problème. Je l'ai eu de 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

Voici ma solution alternative.

Recherchez un UIView en tant que pivot, définissez sa contrainte de disposition supérieure sur un espace vertical fixe sur le dessus du conteneur.

Faites glisser cette contrainte de mise en forme en tant que commande IBOutlet, telle que

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;

Enfin, il suffit de remplacer la méthode viewWillLayoutSubviews de UIViewController comme suit

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    self.topLayoutConstraint.constant = [self.topLayoutGuide length] + YOUR_TOP_CONSTRSINT;
}

La contrainte supérieure de toutes les autres vues est basée sur cette vue pivot, tout est fait :)

14
ananfang

Bien sûr, vous pouvez non seulement ajouter une contrainte entre une vue et le top layout guide ou bottom layout guide par programmation, mais vous pouvez également supprimer et accéder à la contrainte entre une vue et le top and bottom layout guide à l’aide de KVConstraintExtensionsMaster library.

// 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
keshav vishwkarma

Jusqu'à présent, même en utilisant XCode 6, je ne peux pas aligner les contrôles sur le guide de présentation supérieur sur les fichiers .xib. Au lieu de cela, j'utilise une autre manière.

Tout d'abord, dans le générateur d'interface, j'aligne toujours les contrôles sur la bordure supérieure de la vue de viewcontroler.

Ensuite, dans la méthode viewDidLoad, je remplace certaines contraintes afin qu'elles s'alignent sur le guide de présentation supérieur au lieu de la vue principale:

- (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;
}

Pensez que ce n'est pas la meilleure solution car nous remplaçons les objets que nous définissons dans le générateur d'interface. Mais ce peut être une autre façon de penser.

6
Cao Huu Loc

Je pense que la raison pour laquelle ils ne figurent pas dans la XIB est qu’il n’ya aucune connaissance de la hiérarchie du contrôleur de vue dans cette situation, alors que dans un story-board, IB peut indiquer où se trouvent les guides de la hiérarchie du contrôleur de vue dans laquelle se trouve la vue. Par exemple, s'il est contenu dans un UINavigationController, il peut déterminer que le guide de présentation supérieur se trouve sous la barre d'outils de navigation.

5
David Pettigrew

La réponse de Cao Huu Loc avec 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