web-dev-qa-db-fra.com

Le paramètre de hauteur de ligne de cellule personnalisé dans le storyboard ne répond pas

J'essaie de régler la hauteur des cellules pour l'une des cellules de la vue de la table. J'ajuste la taille à partir du paramètre "hauteur de la ligne" dans "l'inspecteur de la taille" de la cellule en question. Lorsque je lance l'application sur mon iPhone, la taille par défaut de la cellule est définie dans la "taille de la ligne" de la vue Tableau.

Si je modifie la "taille de ligne" de la vue tableau, la taille de toutes les cellules change. Je ne veux pas faire cela car je veux une taille personnalisée pour une seule cellule. J'ai vu beaucoup de publications qui proposent une solution programmatique au problème, mais je préférerais le faire via un scénario, si cela est possible.

205
zirinisp

Sur dynamic cells, rowHeight défini sur UITableView remplace toujours le paramètre rowHeight des cellules individuelles.

Mais sur static cells, la variable rowHeight définie sur des cellules individuelles peut remplacer celle de UITableView.

Vous ne savez pas si c'est un bug, Apple pourrait le faire intentionnellement?

287
pixelfreak

Si vous utilisez UITableViewController, implémentez cette méthode:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

Dans la fonction d'une ligne, vous pouvez choisir la hauteur. Par exemple,

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
       return 100;
    } 
    else {
       return 60;
    }
}

Dans cet exemple, la hauteur de la première ligne est de 100 pixels et les autres de 60 pixels.

J'espère que celui-ci pourra vous aider.

82
Beber

Pour les cellules dynamiques, rowHeight défini sur UITableView remplace toujours les cellules individuelles rowHeight

Ce comportement est, IMO, un bogue. Chaque fois que vous devez gérer votre interface utilisateur à deux endroits, elle est sujette aux erreurs. Par exemple, si vous modifiez la taille de votre cellule dans le storyboard, vous devez également vous rappeler de la modifier également dans le heightForRowAtIndexPath:. Jusqu'à ce que Apple corrige le bogue, la meilleure solution de contournement consiste à remplacer heightForRowAtIndexPath:, mais utilisez les cellules de prototype réelles du storyboard pour déterminer la hauteur plutôt que d'utiliser nombres magiques . Voici un exemple:

- (CGFloat)tableView:(UITableView *)tableView 
           heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    /* In this example, there is a different cell for
       the top, middle and bottom rows of the tableView.
       Each type of cell has a different height.
       self.model contains the data for the tableview 
    */
    static NSString *CellIdentifier;
    if (indexPath.row == 0) 
        CellIdentifier = @"CellTop";
    else if (indexPath.row + 1 == [self.model count] )
        CellIdentifier = @"CellBottom";
    else
        CellIdentifier = @"CellMiddle";

    UITableViewCell *cell = 
              [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    return cell.bounds.size.height;
}

Cela garantira que toute modification de la hauteur de votre prototype sera automatiquement prise en compte au moment de l'exécution et qu'il vous suffira de gérer votre interface utilisateur à un emplacement: le storyboard.

34
memmons

J'ai construit le code avec les différentes réponses/commentaires suggérés pour que cela fonctionne pour les storyboards qui utilisent des cellules prototypes.

Ce code:

  • Ne nécessite pas que la hauteur de la cellule soit définie ailleurs que dans la place évidente dans le storyboard
  • Cache la hauteur pour des raisons de performance
  • Utilise une fonction commune pour obtenir l'identifiant de cellule pour un chemin d'index afin d'éviter la duplication de la logique

Merci à Answerbot, Brennan et Lensovet.

- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = nil;

    switch (indexPath.section)
    {
        case 0:
            cellIdentifier = @"ArtworkCell";
            break;
         <... and so on ...>
    }

    return cellIdentifier;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
    static NSMutableDictionary *heightCache;
    if (!heightCache)
        heightCache = [[NSMutableDictionary alloc] init];
    NSNumber *cachedHeight = heightCache[cellIdentifier];
    if (cachedHeight)
        return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    <... configure cell as usual...>
22
JosephH

Il y a en fait deux endroits où vous devez changer la hauteur de la ligne, d'abord la cellule (vous l'avez déjà changée) Et maintenant sélectionner la vue Tableau et vérifier l'inspecteur

19
Kristjan H.

Je pense que c'est un bug.

Essayez de régler la hauteur non pas par l'inspecteur des utilitaires, mais en faisant glisser la souris directement sur le story-board.

J'ai résolu ce problème avec cette méthode.

11
Fogni

Si vous utilisez Swift, utilisez comme ceci. N'utilisez pas de storyboard pour sélectionner la hauteur des lignes. Définissez par programme la hauteur des lignes de la table comme ceci, 

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if indexPath.row == 0 || indexPath.row == 1{
        let cell = self.tableView.dequeueReusableCellWithIdentifier("section1", forIndexPath: indexPath) as! Section1TableViewCell
        self.tableView.rowHeight = 150
        cell.label1.text = "hiiiiii"
        cell.label2.text = "Huiiilllllll"
        return cell

    } else {

        let cell = self.tableView.dequeueReusableCellWithIdentifier("section2", forIndexPath: indexPath) as! Section2TableViewCell
        self.tableView.rowHeight = 60
        cell.label3.text = "llll"
        return cell
    }

}
9
Chathuranga Silva

Ouvrez le storyboard dans la vue XML et essayez de modifier l'attribut rowHeight de l'élément souhaité.

Cela a fonctionné pour moi lorsque j'ai essayé de définir rowHeight personnalisé pour ma ligne prototypée . Cela ne fonctionne pas via l'inspecteur, mais via XML, cela fonctionne.

6
Shtirlic

Vous pouvez obtenir la hauteur de UITableviewCell (dans UITableviewController - cellules statiques) à partir du storyboard à l'aide des lignes suivantes.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];

    return height;
}
6
Hiren Panchal

Vous pouvez utiliser le prototype cells avec une height personnalisée, puis appeler cellForRowAtIndexPath: et renvoyer son frame.height.:.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView
                    cellForRowAtIndexPath:indexPath];
    return cell.frame.size.height;
}
5
Henrik Hartz

J'ai récemment lutté avec cela. Mon problème était que les solutions affichées ci-dessus à l'aide de la méthode heightForRowAtIndexPath: fonctionneraient pour iOS 7.1 dans le simulateur, mais auraient ensuite complètement foiré les résultats en basculant simplement vers iOS 8.1.

J'ai commencé à lire davantage sur les cellules à dimensionnement automatique (introduit dans iOS 8, lisez ici ). Il était évident que l'utilisation de UITableViewAutomaticDimension aiderait dans iOS 8. J'ai essayé d'utiliser cette technique et j'ai supprimé l'utilisation de heightForRowAtIndexPath: et le tour est joué, cela fonctionnait parfaitement sous iOS 8 maintenant. Mais iOS 7 ne l'était pas. Que devais-je faire? J'avais besoin de heightForRowAtIndexPath: pour iOS 7 et non pour iOS 8.

Voici ma solution (par souci de brièveté) qui s'inspire de la réponse @JosephH affichée ci-dessus:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.estimatedRowHeight = 50.;
    self.tableView.rowHeight = UITableViewAutomaticDimension;

    // ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
        return UITableViewAutomaticDimension;

    } else {
        NSString *cellIdentifier = [self reuseIdentifierForCellAtIndexPath:indexPath];
        static NSMutableDictionary *heightCache;
        if (!heightCache)
            heightCache = [[NSMutableDictionary alloc] init];
        NSNumber *cachedHeight = heightCache[cellIdentifier];
        if (cachedHeight)
            return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
    }
}

- (NSString *)reuseIdentifierForCellAtIndexPath:(NSIndexPath *)indexPath {
    NSString * reuseIdentifier;
    switch (indexPath.row) {
        case 0:
            reuseIdentifier = EventTitleCellIdentifier;
            break;
        case 2:
            reuseIdentifier = EventDateTimeCellIdentifier;
            break;
        case 4:
            reuseIdentifier = EventContactsCellIdentifier;
            break;
        case 6:
            reuseIdentifier = EventLocationCellIdentifier;
            break;
        case 8:
            reuseIdentifier = NotesCellIdentifier;
            break;
        default:
            reuseIdentifier = SeparatorCellIdentifier;
            break;
    }

    return reuseIdentifier;
}

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO (@ "8.0") provient d'un ensemble de définitions de macros que j'utilise, que j'ai trouvées quelque part (très utile). Ils sont définis comme:

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
4
speby

Si vous souhaitez définir une hauteur de ligne statique, vous pouvez procéder comme suit:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 120;
}
4
Victor Palhares

Le même problème s’est produit lorsqu’on travaillait sur XCode 9 avec Swift 4 .

Add AutoLayout pour les éléments d'interface utilisateur à l'intérieur de la cellule et la hauteur de ligne de cellule personnalisée fonctionnera en conséquence, comme spécifié.

1
Murari Varma

Pour les cellules dynamiques, rowHeight défini sur UITableView remplace toujours le paramètre rowHeight des cellules individuelles. Juste calculer la hauteur dynamique si le contenu à l'intérieur de la ligne.

1
Aks

Étant donné que je n'avais pas trouvé de solution à ce problème via Interface Builder, j'ai décidé d'afficher une solution programmatique au problème dans Swift using deux cellules dynamiques , alors que la question initiale demandait une solution via Interface Builder. Quoi qu'il en soit, je pense que cela pourrait être utile à la communauté Stack Overflow:

    import UIKit

    enum SignInUpMenuTableViewControllerCellIdentifier: String {
       case BigButtonCell = "BigButtonCell"
       case LabelCell = "LabelCell"
    }

    class SignInUpMenuTableViewController: UITableViewController {
            let heightCache = [SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell : CGFloat(50),
                              SignInUpMenuTableViewControllerCellIdentifier.LabelCell : CGFloat(115)]

    private func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> SignInUpMenuTableViewControllerCellIdentifier {
        if indexPath.row == 2 {
            return SignInUpMenuTableViewControllerCellIdentifier.LabelCell
        } else {
            return SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell
        }
    }

   override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
       return self.heightCache[self.cellIdentifierForIndexPath(indexPath)]!
   }

   ...

  }
0
King-Wizard

Ajouté comme commentaire, mais comme réponse pour plus de visibilité: 

Il semble également y avoir un problème si vous initialement configurez une vue sous forme de "cellules statiques" et que vous la changez ensuite en "prototypes dynamiques". J'ai eu un problème où même la méthode de délégué pour heightForRowAtIndexPath était ignorée. Je l'ai d'abord résolu en éditant directement le storyboard XML, puis finalement, j'ai reconstruit la scène du storyboard à partir de zéro, en utilisant des prototypes dynamiques dès le début.

0
Eric Goldberg

La seule vraie solution que j'ai pu trouver est celle-ci

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = ...; // Instantiate with a "common" method you'll use again in cellForRowAtIndexPath:
    return cell.frame.size.height;
}

Cela fonctionne et permet de ne pas avoir un horrible commutateur/si vous dupliquez la logique déjà dans le StoryBoard. Pas sûr de la performance, mais je suppose qu'en arrivant dans cellForRow:, la cellule étant déjà initialisée, elle est aussi rapide. Bien sûr, il y a probablement des dommages collatéraux ici, mais il semble que cela fonctionne bien pour moi ici.

J'ai aussi posté ceci ici: https://devforums.Apple.com/message/772464

EDIT: Ortwin Gentz ​​ m'a rappelé que heightForRowAtIndexPath: sera appelé pour toutes les cellules de la vue tableau, pas seulement pour celles visibles. Cela semble logique puisque iOS a besoin de connaître la hauteur totale pour pouvoir afficher les barres de défilement appropriées. Cela signifie que cela convient probablement pour les petites vues de table (telles que 20 cellules), mais oubliez cela avec une table de 1000 cellules.

Aussi, l'astuce précédente avec XML: Identique au premier commentaire pour moi. La valeur correcte était déjà là.

0
StuFF mc

Une autre chose que vous pouvez faire est d'aller dans votre plan de document, sélectionnez la vue de tableau dans laquelle votre cellule prototype est imbriquée. Ensuite, dans l'inspecteur de taille, modifiez la hauteur souhaitée de la hauteur de ligne dans la vue du tableau et décochez la case Automatique.

0
Amin Rezapour