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.

4voto

GreatWiz Points 66

Vous pouvez ajouter une contrainte d'emplacement supérieure + horizontale entre l'en-tête et le tableau, pour le placer correctement (si l'en-tête lui-même contient toutes les contraintes de mise en page internes nécessaires pour avoir un cadre correct)

dans la méthode viewDidLoad de tableViewController

    headerView.translatesAutoresizingMaskIntoConstraints = false

    tableView.tableHeaderView = headerView

    headerView.widthAnchor.constraint(equalTo: tableView.widthAnchor).isActive = true
    headerView.topAnchor.constraint(equalTo: tableView.topAnchor).isActive = true
    headerView.centerXAnchor.constraint(equalTo: tableView.centerXAnchor).isActive = true

3voto

pfandrade Points 513

Dans la plupart des cas, la meilleure solution consiste simplement à ne pas lutter contre le cadre et à adopter les masques de redimensionnement automatique :

// embrace autoresizing masks and let the framework add the constraints for you
headerView.translatesAutoresizingMaskIntoConstraints = true
headerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

// figure out what's the best size based on the table view width
let width = self.tableView.frame.width
let targetSize = headerView.systemLayoutSizeFitting(CGSize(width: width, height: CGFloat.greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
headerView.frame.size = targetSize
self.tableView.tableHeaderView = headerView

En utilisant les masques de redimensionnement automatique, vous indiquez au framework comment votre vue doit changer de taille lorsque la vue supérieure change de taille. Mais ce changement est basé sur le cadre initial que vous avez défini.

2voto

Hesse Huang Points 11

Ma solution est de créer une nouvelle classe comme ceci.

class BaseTableHeaderView: UIView {

    func sizeToFitBasedOnConstraints(width: CGFloat = Screen.width) {
        let size = systemLayoutSizeFitting(CGSize(width: width, height: 10000),
                                              withHorizontalFittingPriority: .required,
                                              verticalFittingPriority: .fittingSizeLevel)
        frame = CGRect(origin: .zero, size: size)
    }

    override func willMove(toSuperview newSuperview: UIView?) {
        sizeToFitBasedOnConstraints()
        super.willMove(toSuperview: newSuperview)
    }

}

Pour l'utiliser, il suffit d'ajouter toutes vos sous-vues à une instance de BaseTableHeaderView et l'attacher à votre vue de la table.

let tableHeaderView = BaseTableHeaderView()
tableHeaderView.addSubview(...)
tableView.tableHeaderView = tableHeaderView

Il sera automatiquement redimensionné en fonction de ses contraintes.

1voto

Ryan Points 1830

La vue de l'en-tête de ma table est une sous-classe UIView. J'ai créé une seule UIView ContentView dans l'initialisateur, dont les limites sont les mêmes que celles du cadre de la vue de l'en-tête de la table, et j'ai ajouté tous mes objets en tant que sous-vue de cette vue.

Ensuite, ajoutez les contraintes pour vos objets dans la vue d'en-tête de la table. layoutSubviews plutôt que dans l'initialisateur. Cela a résolu le problème.

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:CGRectMake(0, 0, 0, 44.0)];
    if (self) {
        UIView *contentView = [[UIView alloc] initWithFrame:self.bounds];
        contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth;

        // add other objects as subviews of content view

    }
    return self;
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    // remake constraints here
}

1voto

RomanV Points 21

Mon AutoLayout fonctionne très bien :

CGSize headerSize = [headerView systemLayoutSizeFittingSize:CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds), 0) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
headerView.frame = CGRectMake(0, 0, headerSize.width, headerSize.height);
self.tableView.tableHeaderView = headerView;

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