39 votes

contentView pas l'indentation dans iOS 6 UITableViewCell prototype de cellule

Je suis de la configuration personnalisée UITableViewCell à l'aide d'un prototype de cellule dans un Storyboard. Toutefois, toutes les de la UILabels (et d'autres éléments de l'INTERFACE utilisateur) ne semblent pas être ajouté à la cellule de l' contentView, au lieu d'être ajoutée à l' UITableViewCell afficher directement. Cela crée des problèmes lorsque la cellule est mis en mode d'édition, tant que le contenu n'est pas automatiquement décalé/retrait (ce qui se fait, s'ils étaient à l'intérieur de l' contentView).

Est-il possible d'ajouter les éléments de l'INTERFACE utilisateur à l' contentView lors de la pose de la cellule à l'aide de l'Interface Builder/Storyboard/prototype de cellules? Le seul moyen que j'ai trouvé est de créer tout dans code et l'utiliser [cell.contentView addSubView:labelOne] qui ne serait pas idéal, car il est beaucoup plus facile à disposition de la cellule sous forme de graphique.

66voto

Skoota Points 2378

Le complément d'enquête (l'affichage de la sous-vue de la hiérarchie de la cellule) Interface Builder, la place des sous-vues au sein de la cellule de l' contentView, il ne ressemble pas à elle.

La cause racine du problème iOS 6 mise en page automatique. Lorsque la cellule est placée en mode d'édition (et retrait) l' contentView est également en retrait, donc il va de soi que toutes les sous-vues au sein de l' contentView vont évoluer (tiret) en vertu de l'étant au sein de l' contentView. Cependant, toute la mise en page automatique des contraintes appliquées par Interface Builder semblent être par rapport à l' UITableViewCell lui-même, plutôt que de l' contentView. Cela signifie que même si l' contentView tirets, les sous-vues contenues dans n' - les contraintes de prendre en charge.

Par exemple, lorsque j'ai placé un UILabel dans la cellule (et l'a placé 10 points à partir de la gauche de la cellule) IB automatiquement appliqué une contrainte de "l'Espace Horizontal (10)". Cependant, cette contrainte est relative à l' UITableViewCell PAS contentView. Cela signifie que lorsque la cellule est en retrait, et l' contentView se déplace, l'étiquette reste en place comme il est en conformité avec la contrainte de rester 10 points à partir de la gauche de l' UITableViewCell.

Malheureusement (pour autant que je suis au courant) il n'y a aucun moyen de supprimer ces IB créé des contraintes de l'intérieur de l'IB lui-même, donc, voici comment j'ai résolu le problème.

Au sein de l' UITableViewCell sous-classe de la cellule, j'ai créé un IBOutlet pour que la contrainte appelés cellLabelHSpaceConstraint. Vous avez également besoin d'un IBOutlet pour l'étiquette elle-même, que j'ai appelée" cellLabel. J'ai ensuite mis en œuvre l' -awakeFromNib méthode que ci-dessous:

- (void)awakeFromNib {

    // -------------------------------------------------------------------
    // We need to create our own constraint which is effective against the
    // contentView, so the UI elements indent when the cell is put into
    // editing mode
    // -------------------------------------------------------------------

    // Remove the IB added horizontal constraint, as that's effective
    // against the cell not the contentView
    [self removeConstraint:self.cellLabelHSpaceConstraint];

    // Create a dictionary to represent the view being positioned
    NSDictionary *labelViewDictionary = NSDictionaryOfVariableBindings(_cellLabel);   

    // Create the new constraint
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[_cellLabel]" options:0 metrics:nil views:labelViewDictionary];

    // Add the constraint against the contentView
    [self.contentView addConstraints:constraints];

}

En résumé, le ci-dessus va supprimer l'espacement horizontal de la contrainte qui l'IB automatiquement ajouté (comme c'est efficace contre l' UITableViewCell plutôt que de l' contentView) et nous avons ensuite définir et d'ajouter nos propres limites, à l' contentView.

Dans mon cas, tous les autres UILabels dans la cellule ont été positionnées en fonction de la position de l' cellLabel donc quand je fixe la contrainte de positionnement, de cet élément, tous les autres ont suivi, et correctement positionné. Toutefois, si vous avez une disposition plus complexe, alors vous pouvez avoir besoin de faire cela pour d'autres sous-vues ainsi.

32voto

Adrian Points 786

Comme mentionné, XCode, Interface Builder est de cacher les UITableViewCell de contentView. En réalité, tous les éléments de l'INTERFACE utilisateur ajouté à la UITableViewCell sont en fait des sous-vues de la contentView.

Pour le moment, il l'IB n'est pas de faire la même magie pour les contraintes de mise en forme, ce qui signifie qu'ils sont tous exprimés à UITableViewCell niveau.

Une solution de contournement est dans une sous-classe de awakeFromNib pour déplacer tous les NSAutoLayoutConstrains de UITableViewCell à contentView et de les exprimer en termes de contentView :

-(void)awakeFromNib{
  [super awakeFromNib];
  for(NSLayoutConstraint *cellConstraint in self.constraints){
    [self removeConstraint:cellConstraint];
    id firstItem = cellConstraint.firstItem == self ? self.contentView : cellConstraint.firstItem;
    id seccondItem = cellConstraint.secondItem == self ? self.contentView : cellConstraint.secondItem;
    NSLayoutConstraint* contentViewConstraint =
    [NSLayoutConstraint constraintWithItem:firstItem
                                 attribute:cellConstraint.firstAttribute
                                 relatedBy:cellConstraint.relation
                                    toItem:seccondItem
                                 attribute:cellConstraint.secondAttribute
                                multiplier:cellConstraint.multiplier
                                  constant:cellConstraint.constant];
    [self.contentView addConstraint:contentViewConstraint];
  }
}

9voto

Mihaylov Points 91

Ici est une sous-classe, en se basant sur les réponses des idées, je vais baser ma personnalisé cellules sur:

@interface FixedTableViewCell ()

- (void)initFixedTableViewCell;

@end

@interface FixedTableViewCell : UITableViewCell

@end

@implementation FixedTableViewCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (nil != (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
        [self initFixedTableViewCell];
    }
    return self;
}

- (void)awakeFromNib {
    [super awakeFromNib];

    [self initFixedTableViewCell];
}

- (void)initFixedTableViewCell {
    for (NSInteger i = self.constraints.count - 1; i >= 0; i--) {
        NSLayoutConstraint *constraint = [self.constraints objectAtIndex:i];

        id firstItem = constraint.firstItem;
        id secondItem = constraint.secondItem;

        BOOL shouldMoveToContentView = YES;

        if ([firstItem isDescendantOfView:self.contentView]) {
            if (NO == [secondItem isDescendantOfView:self.contentView]) {
                secondItem = self.contentView;
            }
        }
        else if ([secondItem isDescendantOfView:self.contentView]) {
            if (NO == [firstItem isDescendantOfView:self.contentView]) {
                firstItem = self.contentView;
            }
        }
        else {
            shouldMoveToContentView = NO;
        }

        if (shouldMoveToContentView) {
            [self removeConstraint:constraint];
            NSLayoutConstraint *contentViewConstraint = [NSLayoutConstraint constraintWithItem:firstItem
                                                                                     attribute:constraint.firstAttribute
                                                                                     relatedBy:constraint.relation
                                                                                        toItem:secondItem
                                                                                     attribute:constraint.secondAttribute
                                                                                    multiplier:constraint.multiplier
                                                                                      constant:constraint.constant];
            [self.contentView addConstraint:contentViewConstraint];
        }
    }
}

@end

6voto

railwayparade Points 3448

Une alternative à la sous-classement est de réviser les contraintes dans cellForRowAtIndexPath.

Intégrer tout le contenu de la cellule à l'intérieur d'un conteneur de vue. Alors point de l'attaque et de fuite des contraintes de la cellule.contentView plutôt que l'affichage de la table de la cellule.

  UIView *containerView = [cell viewWithTag:999];
  UIView *contentView = [cell contentView];

  //remove existing leading and trailing constraints
  for(NSLayoutConstraint *c in [cell constraints]){
    if(c.firstItem==containerView && (c.firstAttribute==NSLayoutAttributeLeading || c.firstAttribute==NSLayoutAttributeTrailing)){
      [cell removeConstraint:c];
    }
  }

  NSLayoutConstraint *trailing = [NSLayoutConstraint
                                 constraintWithItem:containerView
                                 attribute:NSLayoutAttributeTrailing
                                 relatedBy:NSLayoutRelationEqual
                                 toItem:contentView
                                 attribute:NSLayoutAttributeTrailing
                                 multiplier:1
                                 constant:0];

  NSLayoutConstraint *leading = [NSLayoutConstraint
                                 constraintWithItem:containerView
                                 attribute:NSLayoutAttributeLeading
                                 relatedBy:NSLayoutRelationEqual
                                 toItem:contentView
                                 attribute:NSLayoutAttributeLeading
                                 multiplier:1
                                 constant:0];

  [cell addConstraint:trailing];
  [cell addConstraint:leading];

2voto

Joseph Lord Points 250

Je pense que c'est corrigé dans iOS 7 beta 3 rendant les solutions de contournement inutiles à partir de ce point (mais probablement inoffensifs comme dans la plupart des cas, ils vont se vider les opérations).

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