web-dev-qa-db-fra.com

la hauteur de la vue d'en-tête de tableau est incorrecte lors de l'utilisation de la présentation automatique, de l'IB et de la taille des polices

J'essaie de créer une vue d'en-tête pour mon uiTableView (pas un en-tête de section, je les ai déjà.) J'ai configuré un XIB dans le générateur d'interface. Toutes les connexions sont raccordées et tout fonctionne à merveille ... sauf que la table ne lui laisse pas assez de place! Mon problème est que le haut de la table chevauche un peu l'en-tête de la table.

Mon XIB est configuré avec la lecture automatique pour tous les boutons et IB est heureux que les contraintes ne soient pas en conflit/ambiguë. La vue est définie sur Taille libre, ce qui dans mon cas a finalement été de 320 x 471. Ensuite, dans les contraintes relatives à la vue, j'ai défini une taille intrinsèque pour la vue identique.

Maintenant cela fonctionne parfaitement avec ma table. Tout a l'air super. Mais si je modifie manuellement l'une des polices dans la vue d'en-tête avec du code, la disposition rend la vue plus grande et se termine sous mon tableau.

Des idées sur la manière de faire en sorte que tableviewcontroller laisse suffisamment de place pour la vue en-tête après la définition des polices et des tailles? J'espère que j'ai eu du sens en expliquant cela.

31
jedipixel

Remarque: une version de Swift 3+ est disponible ici: https://Gist.github.com/marcoarment/1105553afba6b4900c10#gistcomment-1933639


L'idée est de calculer la hauteur de l'en-tête à l'aide de systemLayoutSizeFittingSize:targetSize.

Retourne la taille de la vue qui satisfait les contraintes qu'elle contient . Détermine la taille optimale de la vue en tenant compte de toutes les contraintes détient et ceux de ses sous-vues.

Après avoir modifié la hauteur de l'en-tête, il est nécessaire de réaffecter la propriété tableHeaderView pour ajuster les cellules du tableau.

Sur la base de cette réponse: Utilisation de la disposition automatique dans UITableView pour des dispositions de cellules dynamiques et des hauteurs de rangées variables

- (void)sizeHeaderToFit
{
    UIView *header = self.tableView.tableHeaderView;

    [header setNeedsLayout];
    [header layoutIfNeeded];

    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
    CGRect frame = header.frame;

    frame.size.height = height;
    header.frame = frame;

    self.tableView.tableHeaderView = header;
}
64
vokilam

J'ai rencontré un problème similaire lorsque j'essayais de définir l'en-tête de la vue tableau sur une vue personnalisée définie avec la présentation automatique à l'aide du générateur d'interface.

Quand j’ai fait cela, j’aurais trouvé qu’il serait masqué par un en-tête de section.

Mon travail consistait à utiliser une "vue factice" comme vue d'en-tête de tableau, puis à ajouter ma vue personnalisée à cette vue factice en tant que sous-vue. Je pense que cela permet à la disposition automatique de configurer l'apparence en fonction des contraintes et du cadre de la vue contenant. Ce n'est probablement pas aussi élégant que la solution de vokilam, mais cela fonctionne pour moi.


CGRect headerFrame = CGRectMake(0, 0, yourWidth, yourHeight);
UIView *tempView = [[UIView alloc] initWithFrame:headerFrame];
[tempView setBackgroundColor:[UIColor clearColor]];
YourCustomView *customView = [[YourCustomView alloc] initWithFrame: headerFrame];
[tempView addSubview:movieHeader];
self.tableView.tableHeaderView = tempView;
14
rmigneco

Parce que votre tableHeaderView est sous la forme xib avec mise en page automatique, les contraintes de votre coutume headerView et de superView sont inconnues. Vous devez ajouter le constraints de votre coutume headerView:

1.in viewDidLLoad Affectez votre headerView personnalisé à la tableHeaderView de la table.

 - (void)viewDidLoad
{
    [super viewDidLoad];
    UIView *yourHeaderView = [[[NSBundle mainBundle] loadNibNamed:@"yourHeaderView" owner:nil options:nil] objectAtIndex:0];
    //important:turn off the translatesAutoresizingMaskIntoConstraints;Apple documents for details
     yourHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
    self.tableView.tableHeaderView = yourHeaderView;
}

2.in - (void) updateViewConstraints, ajoutez les contraintes essentielles de votre headerView personnalisé

- (void)updateViewConstraints
{
    NSDictionary *viewsDictionary = @{@"headerView":yourHeaderView};

    NSArray *constraint_V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[headerView(121)]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];

    NSArray *constraint_H = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[headerView(320)]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];
    [self.headerView addConstraints:constraint_H];
    [self.headerView addConstraints:constraint_V];

    NSArray *constraint_POS_V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[headerView]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];

    NSArray *constraint_POS_H = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerView]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];
    [self.tableView addConstraints:constraint_POS_V];
    [self.tableView addConstraints:constraint_POS_H];

    [super updateViewConstraints];
}

OK! PS: voici le document associé: Redimensionnement des vues du contrôleur de vues

9
mayqiyue

Voici ce qui a résolu mon problème:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    sizeHeaderToFit()
}

private func sizeHeaderToFit() { 
    if let headerView = tableView.tableHeaderView {

        headerView.setNeedsLayout()
        headerView.layoutIfNeeded()

        let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
        var newFrame = headerView.frame

        // Needed or we will stay in viewDidLayoutSubviews() forever
        if height != newFrame.size.height {
            newFrame.size.height = height
            headerView.frame = newFrame

            tableView.tableHeaderView = headerView
        }
    }
}

J'ai trouvé cette solution quelque part et j'ai travaillé comme un charme, je ne me souviens plus où.

5
ClockWise

J'ai trouvé la réponse de vokilam au travail formidable. Voici sa solution dans Swift.

func sizeHeaderToFit() {
    guard let header = tableView.tableHeaderView else { return }
    header.setNeedsLayout()
    header.layoutIfNeeded()
    let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    header.frame.size.height = height
    tableView.tableHeaderView = header
}
3
Mr Rogers

Les autres réponses m'ont orienté dans la bonne direction pour obtenir le redimensionnement approprié de tableHeaderView. Cependant, je devenais un écart entre l'en-tête et les cellules de tableView. Cela pourrait également entraîner le chevauchement de vos cellules avec votre en-tête, selon que l'en-tête s'agrandit ou diminue. 

Je suis parti de ça:

 tableView.reloadData()
 let height = tableViewHeader.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
 tableView.tableHeaderView?.frame.size.height = height

Pour corriger le décalage/chevauchement, tout ce que je devais faire était de déplacer tableView.reloadData () après avoir défini la nouvelle hauteur plutôt qu'avant. 

Pour ça:

 let height = tableViewHeader.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
 tableView.tableHeaderView?.frame.size.height = height
 tableView.reloadData()
1
templeman15

Combinaison des réponses de @SwiftArchitect, @vokilam et @mayqiyue et utilisation d'une variable tableHeaderView créée par programme au lieu d'une pointe (bien que je ne vois aucune raison pour laquelle cela ne fonctionnerait pas avec une pointe), sous iOS 10.x/Xcode 8.2.1, voici ce que j'ai en train de travailler:

Créez la vue dans les méthodes -viewDidLoad ou -init de votre contrôleur de vue, ou partout où vous utilisez la vue tableau:

MyCustomTableHeaderView *myCustomTableHeaderView = [[MyCustomTableHeaderView alloc] init]; // Don't set its frame
myCustomTableHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
self.myTableView.tableHeaderView = myCustomTableHeaderView;
self.myCustomTableHeaderView = myCustomTableHeaderView;  // We set and update our constraints in separate methods so we store the table header view in a UIView property to access it later

Où que vous configuriez les contraintes de votre vue d'en-tête personnalisé (cela peut être dans `updateConstraints mais cette méthode peut être appelée plusieurs fois):

// We use Pure Layout in our project, but the workflow is the same:
// Set width and height constraints on your custom view then pin it to the top and left of the table view
// Could also use VFL or NSLayoutConstraint methods
[self.myCustomTableHeaderView autoSetDimension:ALDimensionWidth toSize:CGRectGetWidth(self.superview.frame)]; // Width set to tableview's width
[self.myCustomTableHeaderView autoSetDimension:ALDimensionHeight toSize:height]; // Whatever you want your height to be
[self.myCustomTableHeaderView autoPinEdgeToSuperviewEdge:ALEdgeTop];
[self.myCustomTableHeaderView autoPinEdgeToSuperviewEdge:ALEdgeLeft];

// This is important
[self.myCustomTableHeaderView layoutIfNeeded]; // We didn't need to call -setNeedsLayout or reassign our custom header view to the table view's tableHeaderView property again, as was noted in other answers
1
Evan R

Dans mon cas, systemLayoutSizeFittingSize renvoie une taille incorrecte, car l'une des sous-vues utilise le format d'image (largeur en hauteur) 4: 1.

Après avoir modifié la valeur de contrainte de hauteur constante (100), il commence à fonctionner comme prévu.

1
Vitaliy Gozhenko

sizeHeaderToFit suggéré par @vokilam n'a pas fonctionné pour moi.

Ce qui a fonctionné est une version modifiée de @mayqiyue, invoquée pendant viewDidLoad, hauteur câblée, largeur égale à la vue tableau.

// Anchor the headerview, and set width equal to superview
NSDictionary *viewsDictionary = @{@"headerView":self.tableView.tableHeaderView,
                                  @"tableView":self.tableView};

[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[headerView]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerView]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[headerView(==tableView)]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
[self.tableView.tableHeaderView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[headerView(121)]"
                                                                                       options:0
                                                                                       metrics:nil
                                                                                         views:viewsDictionary]];
0
SwiftArchitect

La réponse de @rmigneco a fonctionné pour moi, alors voici la version Swift:

let headerFrame = CGRectMake(0, 0, 100, 1);
let tempView = UIView(frame: headerFrame);
tempView.backgroundColor = UIColor.clearColor()

let yourCustomView = CustomView(frame: headerFrame)
tempView.addSubview(yourCustomView)

self.tableView.tableHeaderView = tempView
0
gmogames

Le code ci-dessous a fonctionné pour moi: - Ajoutez-le dans votre classe UIView -

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

if (self) {
    self.frame = CGRectMake(0, 0, self.frame.size.width, [[self class] height]);
}

return self;

}

0
iosDeveloper