141 votes

Comment redimensionner la vue principale pour qu'elle s'adapte à toutes les vues secondaires avec autolayout ?

D'après ce que je comprends de l'autolayout, il prend la taille de la vue supérieure et, sur la base des contraintes et des tailles intrinsèques, il calcule la position des vues secondaires.

Y a-t-il un moyen d'inverser ce processus ? Je veux redimensionner la vue supérieure sur la base des contraintes et des tailles intrinsèques. Quel est le moyen le plus simple d'y parvenir ?

J'ai une vue conçue dans Xcode que j'utilise comme en-tête pour UITableView . Cette vue comprend une étiquette et un bouton. La taille de l'étiquette diffère selon les données. Selon les contraintes, l'étiquette réussit à pousser le bouton vers le bas ou s'il y a une contrainte entre le bouton et le bas de la vue supérieure, l'étiquette est compressée.

J'ai trouvé quelques questions similaires mais elles n'ont pas de réponses bonnes et faciles.

149voto

TomSwift Points 22012

L'API correcte à utiliser est UIView systemLayoutSizeFittingSize: en passant soit UILayoutFittingCompressedSize o UILayoutFittingExpandedSize .

Pour un UIView en utilisant autolayout, cela devrait fonctionner tant que vos contraintes sont correctes. Si vous voulez l'utiliser sur un UITableViewCell (pour déterminer la hauteur de la ligne, par exemple), vous devez l'appeler dans votre cellule. contentView et saisir la hauteur.

D'autres considérations existent si vous avez un ou plusieurs UILabel dans votre vue qui sont multi-lignes. Dans ce cas, il est impératif que l'élément preferredMaxLayoutWidth soit correctement définie de manière à ce que l'étiquette fournisse un code d'accès correct. intrinsicContentSize qui sera utilisé dans systemLayoutSizeFittingSize's calcul.

EDIT : à la demande, ajout d'un exemple de calcul de la hauteur d'une cellule d'un tableau.

L'utilisation de la mise en page automatique pour le calcul de la hauteur des cellules du tableau n'est pas très efficace, mais elle est très pratique, surtout si la cellule a une disposition complexe.

Comme je l'ai dit plus haut, si vous utilisez un fichier multiligne UILabel il est impératif de synchroniser les preferredMaxLayoutWidth à la largeur de l'étiquette. J'utilise un UILabel pour ce faire :

@implementation TSLabel

- (void) layoutSubviews
{
    [super layoutSubviews];

    if ( self.numberOfLines == 0 )
    {
        if ( self.preferredMaxLayoutWidth != self.frame.size.width )
        {
            self.preferredMaxLayoutWidth = self.frame.size.width;
            [self setNeedsUpdateConstraints];
        }
    }
}

- (CGSize) intrinsicContentSize
{
    CGSize s = [super intrinsicContentSize];

    if ( self.numberOfLines == 0 )
    {
        // found out that sometimes intrinsicContentSize is 1pt too short!
        s.height += 1;
    }

    return s;
}

@end

Voici une sous-classe artificielle de UITableViewController démontrant heightForRowAtIndexPath :

#import "TSTableViewController.h"
#import "TSTableViewCell.h"

@implementation TSTableViewController

- (NSString*) cellText
{
    return @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
}

#pragma mark - Table view data source

- (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView
{
    return 1;
}

- (NSInteger) tableView: (UITableView *)tableView numberOfRowsInSection: (NSInteger) section
{
    return 1;
}

- (CGFloat) tableView: (UITableView *) tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath
{
    static TSTableViewCell *sizingCell;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        sizingCell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell"];
    });

    // configure the cell
    sizingCell.text = self.cellText;

    // force layout
    [sizingCell setNeedsLayout];
    [sizingCell layoutIfNeeded];

    // get the fitting size
    CGSize s = [sizingCell.contentView systemLayoutSizeFittingSize: UILayoutFittingCompressedSize];
    NSLog( @"fittingSize: %@", NSStringFromCGSize( s ));

    return s.height;
}

- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
{
    TSTableViewCell *cell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell" ];

    cell.text = self.cellText;

    return cell;
}

@end

Une simple cellule personnalisée :

#import "TSTableViewCell.h"
#import "TSLabel.h"

@implementation TSTableViewCell
{
    IBOutlet TSLabel* _label;
}

- (void) setText: (NSString *) text
{
    _label.text = text;
}

@end

Et, voici une image des contraintes définies dans le Storyboard. Notez qu'il n'y a pas de contraintes de hauteur et de largeur sur l'étiquette - ces contraintes sont déduites de l'attribut intrinsicContentSize :

enter image description here

3voto

chandan Points 1831

Vous pouvez le faire en créant des contraintes et en les connectant via le constructeur d'interface.

Utilisez cette Contraintes d'agencement dans le constructeur d'interface automatique

raywenderlich beginning-auto-layout

Articles d'AutolayoutPG Contraintes - Principes de base

@interface ViewController : UIViewController {
    IBOutlet NSLayoutConstraint *leadingSpaceConstraint;
    IBOutlet NSLayoutConstraint *topSpaceConstraint;
}
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leadingSpaceConstraint;

connectez cette sortie de contrainte avec la contrainte de vos sous-vues ou connectez également la contrainte de la super-vue et définissez-la en fonction de vos besoins comme ceci

 self.leadingSpaceConstraint.constant = 10.0;//whatever you want to assign

J'espère que vous le comprendrez mieux.

-1voto

rdelmar Points 53270

Cela peut être fait pour une subview à l'intérieur d'un plus grand UIView mais cela ne fonctionne pas automatiquement pour headerViews . La hauteur d'un headerView est déterminé par ce qui est renvoyé par tableView:heightForHeaderInSection: vous devez donc calculer le height sur la base de la height de la UILabel plus un espace pour le UIButton et tout padding dont vous avez besoin. Vous devez faire quelque chose comme ça :

-(CGFloat)tableView:(UITableView *)tableView 
          heightForHeaderInSection:(NSInteger)section {
    NSString *s = self.headeString[indexPath.section];
    CGSize size = [s sizeWithFont:[UIFont systemFontOfSize:17] 
                constrainedToSize:CGSizeMake(281, CGFLOAT_MAX)
                    lineBreakMode:NSLineBreakByWordWrapping];
    return size.height + 60;
}

Aquí headerString est la chaîne de caractères que vous souhaitez utiliser pour remplir le champ UILabel et le numéro 281 est le width de la UILabel (tel que défini dans Interface Builder )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X