Problema de restricciones de diseño automático en iOS7 en UITableViewCell


104

Estoy usando restricciones de diseño automático mediante programación para diseñar mis celdas UITableView personalizadas y estoy definiendo correctamente los tamaños de celda en tableView:heightForRowAtIndexPath:

Funciona bien en iOS6 y también se ve bien en iOS7

PERO cuando ejecuto la aplicación en iOS7, este es el tipo de mensaje que veo en la consola:

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]>

Y, de hecho, hay una de las restricciones en esa lista que no quiero:

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

y no puedo establecer la translatesAutoresizingMaskIntoConstraintspropiedad del contentViewen NO => estropearía toda la celda.

44 es la altura de celda predeterminada, pero definí mis alturas personalizadas en el delegado de vista de tabla, entonces, ¿por qué la celda contentView tiene esta restricción? Que podria causar esto?

En iOS6 no está sucediendo y todo se ve bien tanto en iOS6 como en iOS7.

Mi código es bastante grande, por lo que no lo publicaré aquí, pero no dude en solicitar un pastebin si lo necesita.

Para especificar cómo lo estoy haciendo, en la inicialización de la celda:

  • Creo todas mis etiquetas, botones, etc.
  • Configuré su translatesAutoresizingMaskIntoConstraintspropiedad en NO
  • Los agrego como subvistas contentViewde la celda.
  • Añado las restricciones en el contentView

También estoy profundamente interesado en comprender por qué esto sucede solo en iOS7.


¿Cuál es su altura de celda personalizada?
Mike Pollard

mi altura de celda personalizada se establece en 90
Alexis

Un colega tuvo el mismo problema ayer, pero con el ancho predeterminado de 320 (para una aplicación de iPad).
jrturton

Aquí hay un proyecto de muestra que demuestra este mismo problema: github.com/Alex311/TableCellWithAutoLayout Aquí están algunas de mis observaciones al respecto: github.com/Alex311/TableCellWithAutoLayout/commit/…
smileyborg

Me encontré con el mismo error, pero fue porque nunca inicialicé la celda de prototipo adicional que estaba usando para encontrar la altura de mi celda personalizada.
Steve Moser

Respuestas:


132

También tuve este problema ... Parece que el marco de contentView no se actualiza hasta que layoutSubviewsse llama, sin embargo, el marco de la celda se actualiza antes, dejando el marco de contentView configurado {0, 0, 320, 44}en el momento en que se evalúan las restricciones.

Después de mirar el contentView con más detalle, parece que las máscaras de tamaño automático ya no se configuran.

Configurar la máscara automática antes de restringir sus vistas puede resolver este problema:

- (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;
}

Esto hace el trabajo, gracias hombre. ¿Qué podría pasar al utilizar estilos de edición?
Alexis

11
@ L14M333 Vea el código que publiqué en este comentario aquí ; básicamente, debería poder configurar self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);antes de agregar sus restricciones, lo que debería resolver el problema.
smileyborg

2
el autoresizingMask no funciona para mí: la restricción inicial se ha ido pero se agregan las 3 nuevas "<NSAutoresizingMaskLayoutConstraint: 0x8b79740 h = - & - v = - & - UITableViewCellContentView: 0x8b44010.height == UITableViewCellScrollView: 0x8bight4a1" "<NSAutoresizingMaskLayoutConstraint: 0x8b7b9f0 h = - & - v = - & - UITableViewCellScrollView: 0x8b4a130.height == LibraryCell: 0x8ac19d0.height>", "<NSAutoresizingMaskLayout &8b: V7c: Library 0x8ac19d0 (0)]> "
catamphetamine

1
A mí también me funciona, ¡he estado luchando durante una hora! ¡Gracias! <3
mokagio

2
Después de deshacerme de otros problemas de diseño automático (iOS 7 / iOS 8) descubrí que usar self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);funciona tan bien como usar self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;. Puse esto updateConstraintsantes de agregar las restricciones a mi vista de contenido.
prueba el

35

Aparentemente, hay algo mal con UITableViewCell y UICollectionViewCell en iOS 7 usando iOS 8 SDK.

Puede actualizar contentView de la celda cuando la celda se reutiliza de esta manera:

Para Static 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

Dado que los controladores de vista de tabla estática son frágiles y pueden romperse fácilmente si implementa alguna fuente de datos o métodos deletegate, hay comprobaciones que garantizarán que este código solo se compile y ejecute en iOS 7

Es similar para UITableViewController dinámico estándar:

-(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;
}

Para este caso no necesitamos la verificación adicional de compilación, ya que se requiere implementar este método.

La idea es la misma para ambos casos y para UICollectionViewCell, como se comentó en este hilo: El problema de autoresizing del marco de contentView de UICollectionViewCell en la celda del prototipo de Storyboard (Xcode 6, iOS 8 SDK) ocurre cuando se ejecuta solo en iOS 7


1
Esta es la mejor respuesta, o al menos la mejor solución para mí. My Cell (reglas de diseño automático) funcionó muy bien en iOS8 con XCode6 y funcionó muy bien con iOS7 y 6 con XCode 5. Actualizo XCode a XCode6 y ya no funciona en iOS6 y 7. ¡¡¡¡Gracias !!!!
xarly

Esto ya no es un problema con Xcode 6.1. Además, no utilice NSFoundationVersionNumber, consulte nshipster.com/swift-system-version-checking
onmyway133

1
@ onmyway133: ¿Por qué esto ya no es un problema en Xcode 6.1? Todavía tengo el problema incluso si uso Xcode 6.1 y iOS 8.1 SDK. El problema solo ocurre en iOS 7. Cambiar los límites o establecer una máscara de tamaño automático resuelve el problema. Pero utilicé el enfoque indicado en la respuesta más votada o en los comentarios de la misma.
prueba el

Sí, esta es la mejor respuesta basada en mi búsqueda en Google de 3 horas. Otras "soluciones" similares no proporcionan la lista completa de cell.contentView.autoresizingMask. Solo este funciona para mi proyecto de iPad 7.1 creado en Xcode 6.
Golden Thumb

13

Como las celdas se están reutilizando y la altura puede cambiar en función del contenido, creo que, en general, sería mejor establecer la prioridad de los espacios a menos de lo requerido.

En su caso, UIImageView tiene un espaciado de 15 hacia la parte superior y la vista inferior tiene un espaciado de 0 hacia la parte inferior. Si establece la prioridad de esas restricciones en 999 (en lugar de 1000), la aplicación no se bloqueará porque las restricciones no son necesarias.

Una vez que se llama al método layoutSubviews, la celda tendrá la altura correcta y las restricciones se pueden satisfacer normalmente.


¡Eres un genio! solución agradable y limpia gracias :)
Blacky

9

Sigo sin encontrar una buena solución para guiones gráficos ... También hay información aquí: https://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

Por lo que aconsejan allí:

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

He inducido mi solución:

  • haga clic derecho en el guión gráfico
  • Abrir como -> Código fuente
  • busque la cadena "44" allí
  • va a ser como

.

<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"/>

.

  • reemplace rowHeight = "44" con rowHeight = "9999" y altura = "44" con altura = "9999"
  • haga clic derecho en el guión gráfico
  • Abrir como -> Interface Builder
  • ejecuta tu aplicación y verifica la salida

Esto funcionó para mí. Había creado un UITableViewController en el guión gráfico donde algunas celdas se crearon a partir de un prototipo y otras completamente en código al crear una instancia de una clase.
Atharva

3

Simplemente aumente la altura de celda predeterminada. Parece que el problema es que el contenido de la celda es mayor que el tamaño de celda predeterminado (inicial), violando algunas restricciones de no negatividad hasta que la celda cambia de tamaño a su tamaño real.


De hecho, mis celdas son más altas que el tamaño predeterminado, pero ¿cómo sucede que se usa el tamaño predeterminado desde que el delegado de tableview implementa tableView: heightForRowAtIndexPath:?
Alexis

Probablemente, las celdas se crean con el tamaño predeterminado y luego se redimensionan al tamaño real.
Vadim Yelagin

de hecho, funciona, pero ¿por qué entonces no sucede en iOS6?
Alexis

3
@jafar iOS 7 cambió muchas cosas en las celdas de vista de tabla. En iOS 7, ahora hay una vista de desplazamiento (de tipo UITableViewCellScrollView) entre la celda de vista de tabla y contentView; eso probablemente explica la diferencia entre iOS 6 y 7 aquí.
smileyborg

3

Tal vez establezca la prioridad de la vista en más de 750 y menos de 1000 puede resolver.

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

2

Yo tuve el mismo problema. Mi solución basada en otras anteriores:

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

Saludos, Alessandro


2
De los documentos de Apple:You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.
Ricardo Sanchez-Saez

Quiero comenzar una religión rezándote. He estado buscando HORAS tratando de solucionar este problema, y ​​esto lo resuelve (además de configurar contentView.bounds en CGRectMake (0, 0, 99999, 99999);) - ESTE ES UN ERROR EN EL CÓDIGO DE MANZANAS. Por lo tanto, estoy respetuosamente en desacuerdo con los documentos de Apple que dicen que no llames a esa función. Apple, arregla tu mierda.
Ryan Copley

0

También he enfrentado este problema y ninguna de las sugerencias ayudó. En mi caso, tenía una celda de selección de tamaño y contenía collectionView dentro (cada celda de collectionView contenía una imagen de tamaño completo). Ahora, la altura del tamaño de celda era un poco mayor (60) que la vista de colección (50) y las imágenes dentro de ella (50). Debido a que la vista collectionView tiene una restricción de alineación inferior a la supervista con un valor de 10. En ese caso, recibo una advertencia, y la única forma de solucionarlo era hacer que la altura de la celda fuera la misma que su collectionView.


0

Terminé sin usar UITableViewCell en el diseñador en absoluto ... Creo una vista personalizada y la agrego a la vista de contenido de la celda mediante programación ... Con algunas categorías de ayuda tampoco hay un código repetitivo ...


0

Si funciona bien en iOS8 y recibe la advertencia en iOS7, puede buscar el código fuente del guión gráfico y encontrar el tableviewCell correcto, luego agregar el atributo rect después de la línea tableviewCell. Gracias a kuchumovn .

<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.