web-dev-qa-db-fra.com

Problème de mise en page automatique sur iOS7 dans UITableViewCell

J'utilise des contraintes de mise en page automatique par programme pour la mise en page de mes cellules UITableView personnalisées et je définis correctement les tailles de cellule dans tableView:heightForRowAtIndexPath:

Cela fonctionne très bien sur iOS6 et il fait regardez bien aussi dans iOS7

MAIS lorsque je lance l'application sur iOS7, voici le genre de message que je vois dans la console:

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2013-10-02 09:56:44.847 Vente-Exclusive[76306:a0b] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
        "<NSLayoutConstraint:0xac4c5f0 V:|-(15)-[UIImageView:0xac47f50]   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",
        "<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>",
        "<NSLayoutConstraint:0xac43680 V:[UIView:0xac4d0f0(1)]>",
        "<NSLayoutConstraint:0xac436b0 V:[UIView:0xac4d0f0]-(0)-|   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>

Et en effet il y a une des contraintes de cette liste que je ne veux pas:

"<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"

et je ne peux pas définir la propriété translatesAutoresizingMaskIntoConstraints de la contentView sur NO => cela endommagerait la cellule entière.

44 est la hauteur de cellule par défaut, mais j'ai défini mes hauteurs personnalisées dans le délégué de la vue tableau. Pourquoi la cellule contentView a-t-elle cette contrainte? Qu'est-ce qui pourrait causer ça?

Dans iOS6, cela ne se produit pas et tout semble aller pour iOS6 et iOS7.

Mon code est assez gros donc je ne le posterai pas ici, mais n'hésitez pas à demander une Pastebin si vous en avez besoin.

Pour spécifier comment je le fais, sur l'initialisation des cellules:

  • Je crée toutes mes étiquettes, boutons, etc.
  • Je règle leur propriété translatesAutoresizingMaskIntoConstraints sur NO
  • Je les ajoute en tant que sous-vues du contentView de la cellule
  • J'ajoute les contraintes sur le contentView

Je suis également profondément intéressé à comprendre pourquoi cela se produit uniquement sur iOS7.

104
Alexis

J'ai eu ce problème aussi .. Il semble que le cadre de contentView ne soit pas mis à jour tant que layoutSubviews n'est pas appelé, mais le cadre de la cellule est mis à jour plus tôt, le cadre de contentView étant défini sur {0, 0, 320, 44} au moment où les contraintes sont évaluées.

Après avoir examiné contentView de manière plus détaillée, il semble que le redimensionnement automatique des masques ne soit plus défini.

La définition du masque autoresizing avant de contraindre vos vues peut résoudre ce problème:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    if (self)
    {
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
        [self loadViews];
        [self constrainViews];
    }
    return self;
}
132
liamnichols

Apparemment, il y a quelque chose qui ne va pas avec UITableViewCell et UICollectionViewCell sur iOS 7 avec iOS 8 SDK.

Vous pouvez mettre à jour le contenu de la cellule lorsque la cellule est réutilisée comme ceci:

Pour Statable UITableViewController:

#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }

    //your code goes here

    return cell;
}

#endif
#endif

Étant donné que les contrôleurs de vue de table statique sont fragiles et peuvent facilement être cassés si vous implémentez des méthodes de source de données ou de suppression, certaines vérifications garantiront que ce code ne sera compilé et exécuté sur iOS 7.

Il en est de même pour UITableViewController dynamique standard:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"CellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }
    //your code goes here       
    return cell;
}

Dans ce cas, nous n'avons pas besoin de la vérification supplémentaire de la compilation, car l'implémentation de cette méthode est requise.

L'idée est la même dans les deux cas et pour UICollectionViewCell, comme indiqué dans ce fil de discussion: édition automatique du cadre de UICollectionViewCell contentView dans la cellule prototype de Storyboard (Xcode 6, iOS 8 SDK) lors de l'exécution sur iOS 7 uniquement

35
KoCMoHaBTa

Lorsque les cellules sont réutilisées et que la hauteur peut changer en fonction du contenu, je pense qu'en général, il serait préférable de définir la priorité des espacements sur une valeur inférieure à celle requise.

Dans votre cas, UIImageView a un espacement de 15 vers le haut et la vue du bas a un espacement de 0 vers le bas. Si vous définissez la priorité de ces contraintes sur 999 (au lieu de 1 000), l'application ne plantera pas, car les contraintes ne sont pas obligatoires.

Une fois la méthode layoutSubviews appelée, la hauteur de la cellule sera correcte et les contraintes pourront être satisfaites normalement.

13
Steven

Je n'ai toujours pas trouvé de bonne solution pour les storyboards ... Quelques informations également ici: https://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

D'après ce qu'ils conseillent là-bas:

self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);

J'ai induit ma solution:

  • clic droit sur le storyboard
  • Ouvrir en tant que -> Code source
  • cherchez la chaîne "44" ici
  • ça va être comme

.

<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="44" ...
    <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ChatMessageCell" id="bCG-aU-ivE" customClass="ChatMessageCell">
        <rect key="frame" x="0.0" y="22" width="320" height="44"/>

.

  • remplacer rowHeight = "44" par rowHeight = "9999" et height = "44" par height = "9999"
  • clic droit sur le storyboard
  • Ouvrir en tant que -> Interface Builder
  • lancez votre application et vérifiez le résultat
9
asdfasdfads

Définir une priorité d’affichage supérieure à 750 et inférieure à 1 000 peut peut-être résoudre.

"<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",
3
heramerom

Il suffit d'augmenter la hauteur de cellule par défaut. Le problème est que le contenu de la cellule est supérieur à la taille de cellule par défaut (initiale), violant certaines contraintes de non-négativité jusqu'à ce que la cellule soit redimensionnée à sa taille réelle.

3
Vadim Yelagin

J'ai eu le même problème. Ma solution basée sur les autres ci-dessus:

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // initialize my stuff
        [self layoutSubviews]; // avoid debugger warnings regarding constraint conflicts
    }
    return self;
}

Meilleur, Alessandro

1
Cormentis

J'ai fini par ne pas utiliser UITableViewCell dans le concepteur ... Je crée une vue personnalisée et l'ajoute par programme à la vue du contenu de la cellule ... Avec certaines catégories d'aide, il n'y a pas non plus de code "warmplate" ...

0
Renetik

J'ai également fait face à ce problème et aucune des suggestions n'a aidé. Dans mon cas, j'avais une cellule de sélection de taille, et elle contenait collectionView à l'intérieur (chaque cellule collectionView contenait une image en taille réelle). Maintenant, la taille de la cellule était un peu plus grande (60) que la collectionView (50) et les images qu’elle contient (50). En raison de cette vue collectionView, la contrainte d'alignement bottom to superview avec une valeur de 10. Cela m'a donné un avertissement, et le seul moyen de résoudre ce problème était de rendre la hauteur de la cellule identique à celle de sa collectionView.

0
Centurion

Si cela fonctionne correctement dans iOS8 et que l'avertissement apparaît dans iOS7, vous pouvez effectuer une recherche dans le code source du storyboard et trouver le bon tableauviewCell, puis ajouter l'attribut rect après la ligne tableviewCell. Merci à kuchumovn .

<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
0
NSDeveloper