sketch - ios autolayout programmatically
Diseño automático: ¿Qué crea las restricciones llamadas UIView-Encapsulated-Layout-Width & Height? (8)
Es posible que esto no responda a su pregunta, pero podría ayudar a otras personas como yo que llegaron aquí desde la búsqueda.
UIView-Encapsulated-Layout-Width
un extraño error de limitación de UIView-Encapsulated-Layout-Width
acompañado de una UIView-Encapsulated-Layout-Width
porque estaba agregando un tableHeaderView
a una vista de tabla que todavía no se había dimensionado con AutoLayout. Entonces, el sistema intentaba aplicar las restricciones de mis subvistas de encabezado dentro de una tabla con un marco de {0,0,0,0}
. Como a UITableView le gusta el control sobre el ancho de sus elementos, su restricción de ancho generada, UIView-Encapsulated-Layout-Width
, se estableció en cero, causando todo tipo de confusión con mis elementos de encabezado que esperaban un ancho de 320 + pt.
Lo más destacado: asegúrese de agregar / manipular sus vistas suplementarias / encabezado / pie de página después de que AutoLayout haya dimensionado la tabla.
Mis limitaciones de diseño son correctas en Interface Builder, pero se produce una excepción en el tiempo de ejecución gracias a que alguna parte del framework aplica restricciones de altura y ancho fijas que realmente no quiero. ¿Por qué están allí y cómo desactivarlos?
Son las dos últimas restricciones que se muestran en la lista de registro:
2014-04-26 09:02:58.687 BBCNews[32058:60b] 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:0xbf478a0 UIView:0xbf4a3c0.height == 0.28125*UIView:0xbf4a3c0.width>",
"<NSLayoutConstraint:0xbf47190 UIView:0xbf4a3c0.leading == BNMyNewsCell_landscape:0xbf48b10.leading>",
"<NSLayoutConstraint:0xbf47160 UIView:0xbf4a3c0.trailing == BNMyNewsCell_landscape:0xbf48b10.trailing>",
"<NSLayoutConstraint:0xbf47130 BNMyNewsCell_landscape:0xbf48b10.bottom == UIView:0xbf4a3c0.bottom>",
"<NSLayoutConstraint:0xbf47100 UIView:0xbf4a3c0.top == BNMyNewsCell_landscape:0xbf48b10.top>",
"<NSLayoutConstraint:0xd4c3c40 ''UIView-Encapsulated-Layout-Width'' H:[BNMyNewsCell_landscape:0xbf48b10(304)]>",
"<NSLayoutConstraint:0xd4c38a0 ''UIView-Encapsulated-Layout-Height'' V:[BNMyNewsCell_landscape:0xbf48b10(290)]>"
}
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0xbf478a0 UIView:0xbf4a3c0.height == 0.28125*UIView:0xbf4a3c0.width>
Basado en una tonelada de observación, creo (pero no puedo saber con certeza) que las restricciones llamadas UIView-Encapsulated-Layout-Width
y UIView-Encapsulated-Layout-Height
son creadas por UICollectionView
y amigos, y existen para imponer el tamaño devuelto por el sizeForItemAtIndexPath
delegado sizeForItemAtIndexPath
. Supongo que está ahí para garantizar que UICollectionViewCell
configurado por cellForItemAtIndexPath
termine el tamaño que se le dijo que sería.
Lo cual responde mi pregunta inicial aquí. Una segunda pregunta es por qué las restricciones fueron insatisfactorias. La altura intrínseca de la celda debería haber sido la misma que UIView-Encapsulated-Layout-Height
. De nuevo, no lo sé con certeza, pero sospecho que fue un error de redondeo (es decir, la altura intrínseca llegó a 200.1 píxeles, el UIView-Encapsulated-Layout-Height
tal vez se redondeó a 200. La solución que se me ocurrió fue bajar un poco la prioridad de la restricción de celda relevante para permitir que UIView-Encapsulated-Layout-Height
tenga la última palabra.
Definitivamente viendo esto en una UITableView
de tableHeaderView
. Pude hacer que esto funcionara con una vista de encabezado personalizada estableciendo explícitamente el ancho igual al de tableView
después de establecer tableHeaderView
, ENTONCES reiniciándolo después de que se haya completado un pase de diseño.
Código de ejemplo para iOS 9, que supone que tiene un UITableView
pasado a su método como tableView
y un elemento para configurarlo como item
:
//Create the header view
self.contentDetailHeaderView = MyCustomHeaderView()
//Turn on autolayout
self.contentDetailHeaderView.translatesAutoresizingMaskIntoConstraints = false
//Add the header to the table view
tableView.tableHeaderView = self.contentDetailHeaderView
//Pin the width
let widthConstraint = NSLayoutConstraint(item: self.contentDetailHeaderView,
attribute: .Width,
relatedBy: .Equal,
toItem: tableView,
attribute: .Width,
multiplier: 1,
constant: 0)
tableView.addConstraint(widthConstraint)
//Do whatever configuration you need to - this is just a convenience method I wrote on my header view.
self.contentDetailHeaderView.setupForItem(item)
//Lay out the configured view
self.contentDetailHeaderView.layoutIfNeeded()
//Reset the table header view, because ¯/_(ツ)_/¯
tableView.tableHeaderView = self.contentDetailHeaderView
Un par de notas, sobre todo para cuando vuelvo a buscar esto porque tengo el recuerdo de un pez dorado:
- No tiene que llamar esto desde
viewDidLayoutSubviews
: pude utilizar esta técnica siempre que eltableView
tenga el ancho adecuado durante la instalación. - Debe asegurarse de que su vista de encabezado esté configurada para cambiar el tamaño automáticamente. Hice esto creando un
.xib
y luego asegurándome de que todos los elementos estuvieran fijados de modo que a medida que la vista cambiara de ancho, la altura se actualizaría. - Si intentas hacer esto para
viewForHeaderInSection
, probablementeviewForHeaderInSection
mejor queviewForHeaderInSection
algo fuera de la pantalla, lo cual puedes diseñar al estilo de esta técnica . No he tenido mucha suerte con los bits de autoevaluación.
Me estaba encontrando un problema similar al probar Split View en el iPad Pro, y la respuesta de DesignatedNerd funcionó, pero no necesitaba tanto código. Esto es lo que utilicé:
[self.tableView.tableHeaderView setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.myTableHeaderView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.tableView
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0];
NSLayoutConstraint *yConstraint = [NSLayoutConstraint constraintWithItem:self.myTableHeaderView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.tableView
attribute:NSLayoutAttributeTop
multiplier:1
constant:0];
[self.tableView addConstraints:@[widthConstraint, yConstraint]];
Tenga en cuenta la adición de la restricción Y, que vincula la parte superior de tableHeaderView a la parte superior de tableView.
Estaba enfrentando la misma restricción extraña y no tenía idea de por qué, hasta que recordé que la maldita translatesAutoresizingMaskIntoConstraints
propiedadAturasizingMaskIntoConstraints. Establecer esto en false
resolvió el problema. Lo que sucede en segundo plano es que las máscaras de cambio de tamaño automático (el antiguo motor de diseño para iOS) se convierten en restricciones. Muy a menudo no quieres estas restricciones y quieres las tuyas propias. En tales casos, debe establecer esta propiedad en falso y estará bien:
view.translatesAutoresizingMaskIntoConstraints = false
Tuve el mismo problema al agregar restricciones a un encabezado de vista de tabla. Parece que ocurre al agregar restricciones con las constantes establecidas cuando los límites del encabezado eran (0,0,0,0). Logré solucionar esto al solo agregar las restricciones en el método de subvistas de diseño cuando los límites del encabezado no eran (0,0,0,0)
if self.bounds == CGRect.zero {
return
}
Obtuve este error en todo tipo de circunstancias (no necesariamente relacionado con UICollectionView y amigos, tal como lo sugiere la respuesta correcta ).
Entonces mi forma de lidiar con eso fue simplemente eliminar todas las restricciones y luego volver a construirlas (solo que esta vez no tengo miedo de que mis restricciones choquen con las anteriores):
así que en código:
UIView *parentView = [viewInQuestion superview];
[parentView clearConstraintsOfSubview:viewInQuestion];
donde clearConstraintsOfSubview
es un método de categoría en UIView:
- (void)clearConstraintsOfSubview:(UIView *)subview
{
for (NSLayoutConstraint *constraint in [self constraints]) {
if ([[constraint firstItem] isEqual:subview] || [[constraint secondItem] isEqual:subview]) {
[self removeConstraint:constraint];
}
}
}
Hemos comenzado a ver toneladas de conflictos de diseño en iOS 11 que incluyen referencias a estas restricciones y, de hecho, se agregan a través de la bandera de traducirAutoresizingMaskIntoConstraints. Parece que en iOS 11 hay mucha más magia de AutoLayout que sucede cuando una vista se agrega a la jerarquía en lugar de solo cuando se muestra la vista (ya que parecía funcionar en versiones anteriores de iOS). Este es el caso en el que nos encontramos: Crea una vista cuyo diseño interno ayuda a definir el tamaño de las vistas (por ejemplo, la vista tiene restricciones internas que incluyen relleno explícito, etc.)
- *** Agrega esta vista a la jerarquía. - Establezca traduceAutlasizingMaskIntoConstraints en false más tarde, antes de que pase el diseño.
El segundo paso (***) generará un conflicto porque el sistema agregará restricciones de tamaño cero a la vista en el momento en que se agrega la vista a la jerarquía. Estábamos configurando traduceAutlasizingMaskIntoConstraints más tarde como resultado del uso del marco PureLayout que establece automáticamente este indicador correctamente cuando se restringe la vista ... Dicho esto, en iOS 11 debe recordar desactivar traduceAutoresizingMaskIntoConstraints en tiempo de construcción, antes de que se agregue la vista a la jerarquía
Sospecho que Apple pensó que dejar esta bandera en SÍ sería mucho más útil que doloroso. Desafortunadamente, este no ha sido el caso.