Le code que j'avais utilisé pour créer un rectangle (au moins jusqu'à iOS7) était
CGRect rect = [cTableView frame];
rect.Origin.y += [cTableView rowHeight];
searchOverlayView = [[BecomeFirstResponderControl alloc] initWithFrame:rect];
Sur iOS7, cTableView
(une instance de UITableView
) a renvoyé 44
. Le test dans iOS8 avec un iPhone 5s renvoie -1
.
Pourquoi cela arrive-t-il? Quel est le code correct à utiliser pour que mon application soit rétrocompatible avec iOS7?
Apple a modifié la hauteur de ligne par défaut dans iOS8 en UITableViewAutomaticDimension
, déclarée en tant que -1
. Cela signifie que votre vue sous forme de tableau est configurée pour le calcul automatique de la hauteur des cellules.
Vous devrez soit implémenter autoLayout (recommandé), soit implémenter la nouvelle méthode de délégué: heightForRowAtIndexPath
. Voici une excellente question à propos de la présentation automatique: Utilisation de la disposition automatique dans UITableView pour des dispositions de cellules dynamiques et des hauteurs de ligne variables
On dirait que vous avez quand même codé dur (l’ancien par défaut) de toute façon, donc vous pouvez simplement le faire (non recommandé).
Cela m'a fait lutter pendant des heures. J'ai fini par coder la valeur à 44:
self.tableView.rowHeight = 44;
L'implémentation de heightForRowAtIndexPath présente un inconvénient que je préfère ne pas encourir lorsque toutes les lignes d'un tableau ont la même hauteur et ne changent jamais à l'exécution (il est appelé une fois pour chaque ligne, à chaque affichage du tableau).
Dans cette situation, je continue à définir "Row Height" dans XIB et à utiliser le code convivial iOS 8 suivant lorsque j'ai besoin de rowHeight (il fonctionne également sur iOS 7 et versions ultérieures).
NSInteger aRowHeight = self.tableView.rowHeight;
if (-1 == aRowHeight)
{
aRowHeight = 44;
}
Cela vous permet de continuer à éditer librement Row Height dans XIB et fonctionnera même si Apple corrige ce bogue/cette fonctionnalité ultérieurement et si un ensemble XIB Row Height = 44 cesse de revenir à -1.
Si vous modifiez accidentellement la hauteur de ligne dans IB de 44 à quelque chose d'autre (40 par exemple), le calcul automatique de la taille de la cellule échoue. Tu me dois 3 heures, Apple.
Une autre considération est que si vous calculez la hauteur en fonction des dimensions de vue existantes, la méthode heightForRowAtIndexPath
peut être appelée avant viewDidLayoutSubviews
.
Dans ce cas, remplacez viewDidLayoutSubviews
et recalculez la valeur frame.size.height
pour toutes les cellules visibles.
Ma solution à ce problème:
@interface MCDummyTableView () <UITableViewDataSource, UITableViewDelegate>
@end
@implementation MCDummyTableView
- (instancetype) initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
frame = (CGRect){ 0, 0, 100, 100 };
self = [super initWithFrame:frame style:style];
if(!self) return self;
self.dataSource = self;
self.delegate = self;
[self registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CELL"];
return self;
}
- (NSInteger) numberOfSections {
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell*) cellForRowAtIndexPath:(NSIndexPath*)indexPath {
/*
UITableView doesn't want to generate cells until it's in the view hiearchy, this fixes that.
However, if this breaks (or you don't like it) you can always add your UITableView to a UIWindow, then destroy it
(that is likely the safer solution).
*/
return [self.dataSource tableView:self cellForRowAtIndexPath:indexPath];
}
- (UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
return [self dequeueReusableCellWithIdentifier:@"CELL"];
}
- (CGFloat) defaultRowHeight {
return [self cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].frame.size.height;
}
@end
Je n'aime vraiment pas les choses en dur. J'utilise cette classe pour mettre en cache la hauteur de cellule par défaut au début de l'application.