114 votes

Est-il possible d'utiliser AutoLayout avec le tableHeaderView de UITableView ?

Depuis que j'ai découvert AutoLayout Je l'utilise partout, maintenant j'essaie de l'utiliser avec un tableHeaderView .

J'ai fait un subclass de UIView J'ai ajouté tout ce que je voulais (étiquettes etc...) avec leurs contraintes, puis j'ai ajouté ceci CustomView à la UITableView ' tableHeaderView .

Tout fonctionne bien, sauf le UITableView affiche toujours au-dessus de el CustomView par au-dessus de Je veux dire le CustomView es sous el UITableView pour qu'on ne puisse pas le voir !

Il semble que peu importe ce que je fais, les height de la UITableView ' tableHeaderView es toujours 0 (ainsi que la largeur, x et y).

Ma question : est-il possible d'accomplir cette tâche ? sans régler le cadre manuellement ?

EDIT : Le site CustomView ' subview que j'utilise a ces contraintes :

_title = [[UILabel alloc]init];
_title.text = @"Title";
[self addSubview:_title];
[_title keep:[KeepTopInset rules:@[[KeepEqual must:5]]]]; // title has to stay at least 5 away from the supperview Top
[_title keep:[KeepRightInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepLeftInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepBottomInset rules:@[[KeepMin must:5]]]];

J'utilise une bibliothèque pratique, 'KeepLayout', car écrire des contraintes manuellement prend une éternité et nécessite beaucoup trop de lignes pour une seule contrainte, mais les méthodes s'expliquent d'elles-mêmes.

Et le UITableView a ces contraintes :

_tableView = [[UITableView alloc]init];
_tableView.translatesAutoresizingMaskIntoConstraints = NO;
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_tableView];
[_tableView keep:[KeepTopInset rules:@[[KeepEqual must:0]]]];// These 4 constraints make the UITableView stays 0 away from the superview top left right and bottom.
[_tableView keep:[KeepLeftInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepRightInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepBottomInset rules:@[[KeepEqual must:0]]]];

_detailsView = [[CustomView alloc]init];
_tableView.tableHeaderView = _detailsView;

Je ne sais pas si je dois définir des contraintes directement sur l'interface de l'utilisateur. CustomView Je pense que la hauteur de la CustomView est déterminée par les contraintes sur l'interface de l'utilisateur. UILabel "titre" dans celui-ci.

EDIT 2 : Après une autre enquête, il semble que la hauteur et la largeur du CustomView soient correctement calculées, mais le haut du CustomView est toujours au même niveau que le haut du UITableView et ils se déplacent ensemble lorsque je fais défiler.

5voto

Phil Points 105

Code :

  extension UITableView {

          func sizeHeaderToFit(preferredWidth: CGFloat) {
            guard let headerView = self.tableHeaderView else {
              return
            }

            headerView.translatesAutoresizingMaskIntoConstraints = false
            let layout = NSLayoutConstraint(
              item: headerView,
              attribute: .Width,
              relatedBy: .Equal,
              toItem: nil,
              attribute:
              .NotAnAttribute,
              multiplier: 1,
              constant: preferredWidth)

            headerView.addConstraint(layout)

            let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
            headerView.frame = CGRectMake(0, 0, preferredWidth, height)

            headerView.removeConstraint(layout)
            headerView.translatesAutoresizingMaskIntoConstraints = true

            self.tableHeaderView = headerView
          }
  }

5voto

k06a Points 2741

Extension de cette solution http://collindonnell.com/2015/09/29/dynamically-sized-table-view-header-or-footer-using-auto-layout/ pour la vue du pied de table :

@interface AutolayoutTableView : UITableView

@end

@implementation AutolayoutTableView

- (void)layoutSubviews {
    [super layoutSubviews];

    // Dynamic sizing for the header view
    if (self.tableHeaderView) {
        CGFloat height = [self.tableHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
        CGRect headerFrame = self.tableHeaderView.frame;

        // If we don't have this check, viewDidLayoutSubviews() will get
        // repeatedly, causing the app to hang.
        if (height != headerFrame.size.height) {
            headerFrame.size.height = height;
            self.tableHeaderView.frame = headerFrame;
            self.tableHeaderView = self.tableHeaderView;
        }

        [self.tableHeaderView layoutIfNeeded];
    }

    // Dynamic sizing for the footer view
    if (self.tableFooterView) {
        CGFloat height = [self.tableFooterView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
        CGRect footerFrame = self.tableFooterView.frame;

        // If we don't have this check, viewDidLayoutSubviews() will get
        // repeatedly, causing the app to hang.
        if (height != footerFrame.size.height) {
            footerFrame.size.height = height;
            self.tableFooterView.frame = footerFrame;
            self.tableFooterView = self.tableFooterView;
        }

        self.tableFooterView.transform = CGAffineTransformMakeTranslation(0, self.contentSize.height - footerFrame.size.height);
        [self.tableFooterView layoutIfNeeded];
    }
}

@end

5voto

Caleb Friden Points 101

Mise à jour pour Swift 4.2

extension UITableView {

    var autolayoutTableViewHeader: UIView? {
        set {
            self.tableHeaderView = newValue
            guard let header = newValue else { return }
            header.setNeedsLayout()
            header.layoutIfNeeded()
            header.frame.size = 
            header.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
            self.tableHeaderView = header
        }
        get {
            return self.tableHeaderView
        }
    }
}

4voto

David Nix Points 1367

Ce qui suit a fonctionné pour moi.

  1. Utilisez un bon vieux UIView comme vue d'en-tête.
  2. Ajoutez-y des sous-vues UIView
  3. Utiliser l'autolayout sur les sous-vues

Le principal avantage que je vois est de limiter les calculs de trame. Apple devrait vraiment mettre à jour UITableView pour faciliter cette tâche.

Exemple utilisant SnapKit :

let layoutView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 60))
layoutView.backgroundColor = tableView.backgroundColor
tableView.tableHeaderView = layoutView

let label = UILabel()
layoutView.addSubview(label)
label.text = "I'm the view you really care about"
label.snp_makeConstraints { make in
    make.edges.equalTo(EdgeInsets(top: 10, left: 15, bottom: -5, right: -15))
}

4voto

HotJard Points 393

Des choses étranges se produisent. systemLayoutSizeFittingSize fonctionne très bien pour iOS9, mais pas pour iOS 8 dans mon cas. Donc ce problème se résout assez facilement. Il suffit d'obtenir le lien vers la vue du bas dans l'en-tête et dans viewDidLayoutSubviews après le super appel, mettre à jour les limites de la vue de l'en-tête en insérant height comme CGRectGetMaxY(yourview.frame) + padding.

UPD : La solution la plus simple qui soit : Ainsi, dans la vue de l'en-tête, placez la sous-vue et épinglez-la à gauche , droite , top . Dans cette sous-vue, placez vos sous-vues avec des contraintes de hauteur automatique. Après cela, donnez tout le travail à l'autolayout (aucun calcul requis).

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    CGFloat height = CGRectGetMaxY(self.tableView.tableHeaderView.subviews.firstObject.frame);
    self.tableView.tableHeaderView.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), height);
    self.tableView.tableHeaderView = self.tableView.tableHeaderView;
}

En conséquence, la sous-vue s'étend/rétrécit comme elle le devrait, et à la fin, elle appelle viewDidLayoutSubviews. À ce moment-là, nous connaissons la taille réelle de la vue, nous définissons donc la hauteur de la headerView et la mettons à jour en la réaffectant. Tout fonctionne comme sur des roulettes !

Fonctionne également pour la vue du pied de page.

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