¿Debería la contentView.translatesAutoResizingMaskToConstraints de una subclase UICollectionViewCell establecerse en `false`?

TL; DR

Al intentar dimensionar UICollectionViewCells a través del diseño automático, puede obtener fácilmente advertencias de diseño automático incluso con un simple ejemplo.

¿Deberíamos estar estableciendocontentView.translatesAutoResizingMaskToConstraints = false ¿para deshacerse de ellos?

Estoy tratando de crear un UICollectionView conceldas de diseño automático de tamaño automático.

En viewDidLoad:

let layout = UICollectionViewFlowLayout()
layout.estimatedItemSize = CGSize(width: 10, height: 10)
collectionView.collectionViewLayout = layout

Mi celular es muy básico. Es una vista azul única con 75 de ancho y alto para fines de prueba. Las restricciones se crean al anclar la vista a la supervista en los 4 bordes y darle un alto y ancho.

class MyCell: UICollectionViewCell {
  override init(frame: CGRect) {
    view = UIView()

    super.init(frame: frame)

    view.backgroundColor = UIColor.blueColor()
    contentView.addSubview(view)

    installConstraints()
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  var view: UIView

  func installConstraints() {
    view.translatesAutoresizingMaskIntoConstraints = false

    var c: NSLayoutConstraint

    // pin all edges
    c = NSLayoutConstraint(item: contentView, attribute: .Leading, relatedBy: .Equal, toItem: view, attribute: .Leading, multiplier: 1, constant: 0)
    c.active = true
    c = NSLayoutConstraint(item: contentView, attribute: .Trailing, relatedBy: .Equal, toItem: view, attribute: .Trailing, multiplier: 1, constant: 0)
    c.active = true
    c = NSLayoutConstraint(item: contentView, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .Top, multiplier: 1, constant: 0)
    c.active = true
    c = NSLayoutConstraint(item: contentView, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .Bottom, multiplier: 1, constant: 0)
    c.active = true

    // set width and height
    c = NSLayoutConstraint(item: view, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 75)
    c.active = true
    c = NSLayoutConstraint(item: view, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 75)
    c.active = true
  }
}

Cuando ejecuto el código, obtengo dos errores acerca de no poder satisfacer simultáneamente las restricciones:

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) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x7fed88c1bac0 h=--& v=--& H:[UIView:0x7fed8a90c2f0(10)]>",
    "<NSLayoutConstraint:0x7fed8ab770b0 H:[UIView:0x7fed8a90bbe0(75)]>",
    "<NSLayoutConstraint:0x7fed8a90d610 UIView:0x7fed8a90c2f0.leading == UIView:0x7fed8a90bbe0.leading>",
    "<NSLayoutConstraint:0x7fed8ab005f0 H:[UIView:0x7fed8a90bbe0]-(0)-|   (Names: '|':UIView:0x7fed8a90c2f0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fed8ab770b0 H:[UIView:0x7fed8a90bbe0(75)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

(Se omite el segundo error sobre las restricciones verticales, pero es casi idéntico).

Estos errores tienen sentido. Esencialmente, el contentView (0x7fed8a90c2f0) tienetranslatesAutoresizingMask = true, por lo tanto, sus límites establecidos en 10x10 (del tamaño estimado) crean queNSAutoresizingMaskLayoutConstraint restricción. No hay forma de que la vista pueda tener 10 píxeles de ancho y 75 píxeles de ancho, por lo que genera un error.

Intenté varias cosas diferentes para resolver este problema, y solo 2 de ellas parecían funcionar.

Solución 1: establezca al menos una de las restricciones en 999 o menos

En este caso, si cambio la restricción que fija la parte inferior de la vista azul en la parte inferior de contentView a la prioridad 999 (y hago lo mismo con la restricción final), resuelve el problema. Del mismo modo, podría haber elegido Top + Leading, o Width + Height siempre que no tenga 1000 prioridades en todas las direcciones. Al menos uno tiene que "dar" para el diseño inicial.

Aunque puede parecer que esto haría que la vista tuviera una altura / anchura incorrecta, en realidad parece ser del tamaño correcto.

Solución 2: EstablecercontentView.translatesAutoresizingMaskIntoConstraints = false

Al configurar esto enfalse, esencialmente se deshace de laNSAutoresizingMaskLayoutConstraint restricción, y ya no tenemos un conflicto. Por otro lado, dado que contentView no está configurado con un diseño automático para empezar, es como si no importa cómo cambie su marco, su supervista (la celda) nunca va a actualizar su tamaño porque no hay nada que "empuje" de vuelta contra eso.

Sin embargo, esta solución de alguna manera funciona mágicamente. Supongo que en algún momento la celda mira el marco de contentView y decide "oye, me pones a este tamaño, eso probablemente significa que también quieres que la celda tenga este tamaño" y se encarga de cambiar el tamaño de la celda por ti.

¿Qué solución debemos usar?

¿Hay mejores soluciones para este problema? ¿Cuál de los anteriores debe usarse? ¿Hay alguna desventaja en las dos soluciones mencionadas anteriormente, o son esencialmente las mismas y no importa cuál use?

Notas:

La razón por la que es más difícil de ver en ejemplos comoDGSelfSizingCollectionViewCells es porque confían en intrinsicContentSize + contentCompressionResistancePriority. Si se deshace de mis restricciones de ancho + alto, reemplácelas con 1000 llamadas setContentCompressionResistancePriority (horizontal + vertical) y use algo con un tamaño intrínseco (por ejemplo, una etiqueta con texto), ya no verá los errores de diseño automático. Esto implica quewidth@1000 se comportadiferentemente que un ancho intrínseco +contentCompressionResistance@1000. Quizás el momento en que una vista obtiene su ancho intrínseco es después de que está bien modificar el marco de la vista de contenido.

Cosas que no funcionaron:

Noté que cuando creo celdas a través de un guión gráfico, generalmente nunca me encuentro con este problema. Cuando examiné las diferencias en elview de una celda creada a través de un guión gráfico y una creada mediante programación, noté que elautoresizingMask fue RM + BM (36) en el guión gráfico, pero 0 cuando se creó mediante código. Traté de configurar manualmente elautoresizingMask de mi vista azul a 36, pero eso no funcionó. La verdadera razón por la que la solución de guión gráfico funciona es que, por lo general, las restricciones que crea ya están perfectamente configuradas en el guión gráfico (de lo contrario, tendría errores de guión gráfico que deben corregirse). Como parte de la corrección de estos errores, puede cambiar los límites de la celda. Ya que llamainit?(coder:), los límites de la celda ya están configurados correctamente. Entonces, aunque elcontentView.autoresizingMask = true, no hay conflictos ya que ya está definido en el tamaño correcto.En la guía vinculada, se vincula aesta publicación cuando hablamos de crear restricciones. Menciona que deben crearse restricciones enupdateConstraints. Sin embargo, parece que estas fueron las recomendaciones originales de Apple y que sonya no recomiendo esta convención para la mayoría de tus limitaciones. Sin embargo, ya que ese artículo dice crearlos enupdateConstraints Traté en vano. Obtuve los mismos resultados. Esto se debe a que el marco no se actualizó cuando se llamó a updateConstraints (todavía era 10x10).Noté problemas similares cuando eliges un tamaño estimado que es demasiado pequeño. Lo arreglé en el pasado aumentando el tamaño estimado. En este caso probé 100x100, pero todavía causó los mismos errores. Esto tiene sentido ... una vista no puede tener 100 de ancho y 75 de ancho al mismo tiempo. (Tenga en cuenta que considero que configurarlo en 75x75 no es una solución. Consulte a continuación para obtener más información).

No soluciones:

Establecer el tamaño estimado en 75x75. Aunque esto resolverá los errores de este simple ejemplo, no resolverá el problema para las celdas que realmente tienen un tamaño dinámico. Quiero una solución que funcione en todas partes.Devolviendo las dimensiones exactas de la celda encollectionView(_:layout:sizeForItemAtIndexPath:) (por ejemplo, creando una celda de tamaño). Quiero una solución que funcione con mi celular directamente sin necesidad de ningún tipo de contabilidad o cálculo adicional.

Respuestas a la pregunta(1)

Su respuesta a la pregunta