web-dev-qa-db-fra.com

Redimensionner par programme UIView personnalisé à partir de XIB

J'ai le problème suivant: j'ai créé une classe UIView personnalisée et sa présentation dans le fichier XIB. Supposons que la taille de ma vue personnalisée sous XIB soit de 150 x 50. J'ai activé sizeClasses (wAny hAny) et AutoLayout. Dans les métriques simulées, j'ai défini Size = Freeform, Status Bar = None, tous other = Inferred.

Le code de ma classe UIView personnalisée ressemble à ceci:

#import "CustomView.h"

@implementation CustomView

#pragma mark - Object lifecycle

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    if (self) {
        [self setup];
    }

    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];

    if (self) {
        [self setup];
    }

    return self;
}

#pragma mark - Private & helper methods

- (void)setup {
    if (self.subviews.count == 0) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
        self.bounds = self.view.bounds;
        [self addSubview:self.view];
    }
}

@end

Dans ma UIViewController où je veux ajouter cette coutume UIView, j'ai créé le pseudo UIView (taille que j'ai définie dans Interface Builder) où je veux ajouter mes CustomView et j'aimerais que ma CustomView corresponde aux limites de mon conteneur). vue.

J'essaie de faire ça comme ça:

_vCustomView = [[CustomView alloc] init];
_vCustomView.translatesAutoresizingMaskIntoConstraints = NO;
[_vContainer addSubview:_vCustomView];

[_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]];
[_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0]];
[_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
[_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];

Mais pas de chance. Supposons que ma vue conteneur soit de 300 x 100, lorsque j'y ajoute ma UIView personnalisée, ma vue personnalisée est encore de 150 x 50.

J'ai essayé de travailler sans vue conteneur - pour ajouter mon objet personnalisé UIView directement à self.view de ma UIViewController et définir sa largeur et sa hauteur avec:

  • autoLayout contraintes
  • en utilisant initWithFrame lors de l'initialisation de ma UIView personnalisée

mais encore une fois - pas de chance. La vue personnalisée est toujours de 150 x 50.

Quelqu'un peut-il m'expliquer comment puis-je {ajouter par programme ma UIView personnalisée faite dans XIB et la redimensionner à l'aide de contraintes autoLayout?

Merci d'avance.

_ {Edit # 1: Erreur lorsque j'essaie d'exécuter le code d'Andrea sur mon CustomView} _

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) 
(
    "<NSLayoutConstraint:0x17489b760 V:[UIView:0x17418d820(91)]>",
    "<NSLayoutConstraint:0x170c9bf80 V:|-(0)-[CustomView:0x1741da7c0]   (Names: '|':CustomView:0x1741da8b0 )>",
    "<NSLayoutConstraint:0x170c9bfd0 V:[CustomView:0x1741da7c0]-(0)-|   (Names: '|':CustomView:0x1741da8b0 )>",
    "<NSLayoutConstraint:0x170c9be90 V:|-(0)-[CustomView:0x1741da8b0]   (Names: '|':UIView:0x17418d820 )>",
    "<NSLayoutConstraint:0x170c9bee0 CustomView:0x1741da8b0.bottom == UIView:0x17418d820.bottom>",
    "<NSAutoresizingMaskLayoutConstraint:0x170c9dba0 h=--& v=--& CustomView:0x1741da7c0.midY == + 25.0>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x170c9bfd0 V:[CustomView:0x1741da7c0]-(0)-|   (Names: '|':CustomView:0x1741da8b0 )>

_ {Edit # 2: Ca marche!} _

Après @Andrea ajouté:

view.translatesAutoresizingMaskIntoConstraints = NO;

dans son:

- (void) stretchToSuperView:(UIView*) view;

méthode, tout fonctionne comme prévu.

Merci à @Andrea.

13
uerceg

Je suppose que le problème principal est que vous n'utilisez pas la mise en page automatique lorsque vous ajoutez votre xib dans la vue du contenu.
Après avoir ajouté la sous-vue dans vos méthodes init, veuillez appeler cette méthode en passant la vue de la xib:

- (void) stretchToSuperView:(UIView*) view {
    view.translatesAutoresizingMaskIntoConstraints = NO;
    NSDictionary *bindings = NSDictionaryOfVariableBindings(view);
    NSString *formatTemplate = @"%@:|[view]|";
    for (NSString * axis in @[@"H",@"V"]) {
        NSString * format = [NSString stringWithFormat:formatTemplate,axis];
        NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:bindings];
        [view.superview addConstraints:constraints];
    }

}

[MODIFIER]
Votre code de configuration devrait ressembler à ça:

- (void)setup {
    if (self.subviews.count == 0) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
        self.bounds = self.view.bounds;
        [self addSubview:self.view];
        [self stretchToSuperView:self.view];
    }
}

Faites attention à l'intérieur de la vue étendue, j'ai ajouté view.translatesAutoresizingMaskIntoConstraints = NO;
[EDIT 2]
Je vais essayer de développer ma réponse comme demandé. Avec autolayout, lorsque vous ajoutez une vue sans définir de contraintes, autolayout convertit automatiquement les masques de redimensionnement automatique en contraintes, dont la propriété par défaut est UIViewAutoresizingNone, ce qui signifie de ne pas redimensionner automatiquement.
Votre vue XIB a été ajoutée à son parent sans contraintes et sans possibilité de redimensionnement automatique, conservant ainsi sa taille d'origine. Puisque vous voulez que votre vue soit redimensionnée en conséquence, vous avez deux choix:

  • Modifiez les masques de taille automatique de votre vue xib en largeur et en hauteur souples, mais ils doivent correspondre à la taille du parent ou vous ne disposerez pas d'une couverture complète.
  • Ajoutez quelques contraintes qui contraignent les deux vues à être modifiées en conséquence par rapport aux modifications parent. Et vous obtenez cet énoncé entre la vue XIB et sa vue parente, l’espace entre le dernier/dernier et supérieur/inférieur est égal à 0. C’est comme si vous mettiez un peu de colle sur leurs frontières. Pour ce faire, vous devez définir le masque de conversion automatique en contrainte sur NO, ou vous pouvez avoir des conflits lors de la publication dans le journal .

Ce que vous allez faire par la suite consiste à ajouter des contraintes à la vue (hébergeant la vue XIB) dans sa vue d'ensemble, mais il n'y avait aucune contrainte entre XIB et son parent. Autolayout ne sait donc pas comment redimensionner la vue XIB. 
Chaque vue dans une hiérarchie de vues doit avoir ses propres contraintes.
J'espère que cela aide à mieux comprendre.

18
Andrea

Dans votre code, vous devriez avoir quelque chose comme ça:

Tout d’abord, une variable IBOutlet à la contrainte de largeur que vous voulez modifier, soit dans le viewController, soit dans votre CustomView (je ne sais pas vraiment où vous avez la logique pour calculer la valeur de la contrainte).

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

Ensuite, dans la méthode à mettre à jour la valeur constante, vous obtiendrez quelque chose comme ceci:

-(void)updateWidth {
    [self.widthConstraint setConstant:newConstant];
    [self.view layoutIfNeeded]; // self.view must be an ancestor of the view

    //If you need the changes animated, call layoutIfNeeded in an animation block
}

J'espère que cela fonctionne pour toi. Bonne chance!

1
Catalina T.

Fonction Swift 4.0 pour étirer la vue:

Extrait de code:

static public func stretchToSuperView(view:UIView)
    {
        view.translatesAutoresizingMaskIntoConstraints = false
        var d = Dictionary<String,UIView>()
        d["view"] = view
        for axis in ["H","V"] {
            let format = "\(axis):|[view]|"
            let constraints = NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(rawValue: 0), metrics: [:], views: d)
            view.superview?.addConstraints(constraints)
        }
    }

Remarque: Appelez simplement la fonction avec un argument comme sous-vue.

Cela m'aide à résoudre le problème de résolution de .xib dans Swift 4.0.