Estoy configurando una costumbre UITableViewCell utilizando un prototipo de celda en un Storyboard. Sin embargo, todos los UILabels (y otros elementos de interfaz de usuario) no parecen ser añadido a la célula contentView, en lugar de ser agregado a la UITableViewCell ver directamente. Esto crea problemas cuando la célula se pone en modo de edición, como el contenido no cambia automáticamente/sangría (que harían si estuvieran en el interior de la contentView).

Es hay alguna forma de añadir los elementos de interfaz de usuario para el contentView al poner fuera de la célula usando el Interface Builder/Guión/prototipo de células? La única manera que he encontrado es crear todo el código y utilizar [cell.contentView addSubView:labelOne] que no sea muy grande, ya que es mucho más fácil para el diseño de la celda de forma gráfica.

  • Está usted seguro de eso? La última vez que establece una celda en una punta, mientras que parecía que no estaba agregar sub vistas a la vista del contenido, en tiempo de ejecución en el depurador de todo lo que estaba en la vista de contenido. Vale la pena comprobar en el depurador si no lo has hecho ya…
  • Gracias Carl. Usted se haga todas las subvistas se agregan a la contentView. El problema estaba relacionado con iOS 6 autodiseño. He incluido una respuesta en la que se describe cómo el problema se ha solucionado.
InformationsquelleAutor Skoota | 2012-09-26

6 Comentarios

  1. 66

    En la investigación posterior (ver la subvista jerarquía de la célula) Interface Builder hace lugar subvistas dentro de la célula contentView, sólo que no se parece a él.

    La causa raíz del problema era iOS 6 autodiseño. Cuando la célula se coloca en modo de edición (y sangría) el contentView también es irregular, por lo que es lógico que todas las subvistas dentro de la contentView se muevan (guión), por el hecho de estar dentro de la contentView. Sin embargo, todo el autodiseño de las restricciones aplicadas por el Interface Builder parecen ser relativa a la UITableViewCell mismo, en lugar de la contentView. Esto significa que aunque el contentView sangrías, las subvistas contenida dentro de los no – las restricciones de la carga de la toma.

    Por ejemplo, cuando yo pongo un UILabel en el celular (y lo coloca 10 puntos desde el lado izquierdo de la celda) IB aplica automáticamente una restricción «Espacio Horizontal (10)». Sin embargo, esta restricción es relativa a la UITableViewCell NO la contentView. Esto significa que cuando la célula es la sangría, y la contentView se mueve, la etiqueta queda como está cumpliendo con la restricción de permanecer 10 puntos desde el lado izquierdo de la UITableViewCell.

    Por desgracia (según tengo entendido) no hay manera de eliminar estos IB creado dentro de las limitaciones de la IB en sí, así que aquí está cómo he resuelto el problema.

    Dentro de la UITableViewCell subclase de la celda, he creado un IBOutlet para que la restricción de llamadas cellLabelHSpaceConstraint. También se necesita una IBOutlet para la etiqueta en sí, lo que me llama cellLabel. Luego he aplicado el -awakeFromNib método como se indica a continuación:

    - (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 resumen, lo anterior va a quitar el espaciado horizontal de la restricción de que los añade automáticamente (como es eficaz contra la UITableViewCell en lugar de la contentView) y a continuación definimos y añadir nuestra propia restricción a la contentView.

    En mi caso, todos los otros UILabels en la celda se coloca basa en la posición de la cellLabel así que cuando me fijo la restricción/posicionamiento de este elemento en todos los demás siguieron su ejemplo y se coloca correctamente. Sin embargo, si usted tiene un caso más complejo de diseño entonces usted puede necesitar para hacer esto para otros subvistas así.

    • +1 muy interesante el descubrimiento y la solución!
    • Gracias por publicar sus detallada de la solución. Tenía el mismo problema!
    • Usted puede evitar esto mediante el apagado automático en el interface builder, para todo el guión gráfico o simplemente la punta que contiene la celda. Véase la respuesta aquí para obtener más información: stackoverflow.com/questions/12833176/…
    • Sí, eso es correcto. Sin embargo, el diseño automático es muy útil para la orientación de los cambios (en particular dada la complejidad de las células que he diseñado). En mi caso, la sobrecarga de esta solución, manteniendo el diseño automático activada (en lugar de tener completamente relayout la célula de forma manual cuando se gira el dispositivo) es suficiente para justificarlo. Sin embargo, esperemos que esto será corregido en futuras versiones…
    • He mirado en el código generado por el IB y su derecho, todas las restricciones expresadas en términos de TebleViewCell en lugar de la contentView (incluso si el contentView está presente en el XML, pero no se puede acceder desde IB interfaz de usuario). Es posible eliminar una toma de corriente de su solución (cellLabelHSpaceConstraint) mediante la expresión de todas las restricciones de IB con respecto al lado DERECHO de la TableViewCell y dar el uno con restricción de una prioridad menor que 1000. Usando este método, usted sólo necesita una toma de corriente y la restricción original no necesitan ser removidos.
    • +1 Gracias por publicar este – he utilizado y funciona muy bien! Esto parece como un error en la forma en IB maneja restricciones en UITableViewCell de contenido personalizado.
    • Esto sin duda parece una solución para un error. Cuando la vista de la clase es una subclase de UITableViewCell, y las cosas que se añaden a la contentView, parece bastante claro que las restricciones deben estar en el contentView.
    • No olvide llamar a [super awakeFromNib];
    • Lo siento resucitar un hilo viejo, pero estoy teniendo un problema. Estoy usando el guión, así que estoy tratando de agregar a este initWithCoder. Sin embargo, mi etiqueta de salida aún no ha sido cargado en la memoria en initWithCoder. Alguna sugerencia de cómo puede utilizar esta solución con un archivo de guión gráfico? Gracias!!
    • Debo añadir que estoy usando una estática de la célula, por lo que no estoy de ejecución cellForRowAtIndexPath

  2. 32

    Como se ha mencionado, XCode Interfaz del Generador está ocultando la UITableViewCell del contentView. En realidad, todos los elementos de interfaz de usuario añadido a la UITableViewCell son, de hecho, subvistas de la contentView.

    Por el momento, IB no está haciendo la misma magia para restricciones de diseño, lo que significa que todos ellos están expresadas en UITableViewCell nivel.

    Una solución consiste en una subclase de la awakeFromNib para mover todos los NSAutoLayoutConstrains de UITableViewCell a contentView y expresarlos en términos de la 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];
      }
    }
    • Esto funcionó para mí! Gracias!
    • Esto funcionó muy bien! Estaba usando un agrupados vista de tabla y tenía que hacer todo lo relativo a la celda en la interfaz del generador en lugar de a cómo se veía visualmente, pero se trabajó para llegar a guión y clip correctamente!
    • +1 Añadido esto a mi base de UITableViewCell así que nunca voy a tener que lidiar con este nuevo.
    • La solución funciona para mí, pero tenía que hacer un cambio en otros lugares. En lugar de [cell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; que yo llamo [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    • Perfecto! Esto es exactamente lo que IB debería estar haciendo.
  3. 9

    Aquí es una subclase, basado en otras respuestas, ideas, voy a basar mi costumbre células en:

    @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
    • En mi opinión, no hay ningún uso en llamar initFixedTableViewCell de initWithStyle:reuseIdentifier: como se trata de una Interfaz de Generador de error que no puede ocurrir sólo si usted carga el cel de un archivo nib. Esperemos que en el código, no se debe reproducir la Interfaz del Generador de error 😉 yo también no veo por qué de verificación para los descendientes en la lista de restricciones.
    • Esto funcionó bien para mí, pero usted necesita para preservar la restricción de prioridad también: «contentViewConstraint.prioridad = restricción.prioridad»
  4. 6

    Una alternativa a la creación de subclases es revisar las restricciones en cellForRowAtIndexPath.

    Incrustar todo el contenido de la celda dentro de un contenedor de vista. A continuación, elija el principio y el final de restricciones a la celda.contentView en lugar de la vista de tabla de la célula.

      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];
  5. 2

    Creo que esta es fija en iOS 7 beta 3 lo que las soluciones innecesarios a partir de ese punto (pero probablemente inofensivo como en la mayoría de los casos va a quedar vacías de las operaciones).

  6. 1

    Basado en el código por Skoota (soy un principiante, no sé mucho de lo que hizo, pero excelente trabajo) mi sugerencia es poner todas sus cosas en un borde-a-borde contenedor de ver y agregar la siguiente:

    En la celda de encabezado del archivo, tengo el siguiente IBOutlets:

    @property (weak, nonatomic) IBOutlet UIView *container;
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftConstrain;
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *rightConstrain;

    En el archivo de implementación, tengo el siguiente en awakeFromNib:

    //Remove the IB added horizontal constraint, as that's effective gainst the cell not the contentView
    [self removeConstraint:self.leftConstrain];
    [self removeConstraint:self.rightConstrain];
    //Create a dictionary to represent the view being positioned
    NSDictionary *containerViewDictionary = NSDictionaryOfVariableBindings(_container);
    //Create the new left constraint (0 spacing because of the edge-to-edge view 'container')
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-0-[_container]" options:0 metrics:nil views:containerViewDictionary];
    //Add the left constraint against the contentView
    [self.contentView addConstraints:constraints];
    //Create the new constraint right (will fix the 'Delete' button as well)
    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"[_container]-0-|" options:0 metrics:nil views:containerViewDictionary];
    //Add the right constraint against the contentView
    [self.contentView addConstraints:constraints];

    De nuevo, el anterior fue posible por Skoota. Gracias!!! Al de los créditos de ir a él.

Dejar respuesta

Please enter your comment!
Please enter your name here