vertical how buttons ios autolayout uikit ios9 uistackview

ios - how - stackview buttons



UIStackView "No es posible satisfacer simultáneamente las restricciones" en vistas ocultas "aplastadas" (14)

Basado en la respuesta de @ Senseful, aquí hay una extensión UIStackView para ajustar una vista de pila en una vista y aplicar las restricciones que recomienda:

/// wraps in a `UIView` to prevent autolayout warnings when a stack view with spacing is placed inside another stack view whose height might be zero (usually due to `hidden` being `true`). /// See http://stackoverflow.com/questions/32428210 func wrapped() -> UIView { let wrapper = UIView() translatesAutoresizingMaskIntoConstraints = false wrapper.addSubview(self) for attribute in [NSLayoutAttribute.Top, .Left, .Right, .Bottom] { let constraint = NSLayoutConstraint(item: self, attribute: attribute, relatedBy: .Equal, toItem: wrapper, attribute: attribute, multiplier: 1, constant: 0) if attribute == .Bottom { constraint.priority = 999 } wrapper.addConstraint(constraint) } return wrapper }

En lugar de agregar su stackView , use stackView.wrapped() .

Cuando mis "filas" UIStackView se aplastan, arrojan advertencias de AutoLayout . Sin embargo, se muestran bien y nada más está mal además de este tipo de registros:

Incapaz de satisfacer simultáneamente las restricciones. Probablemente al menos una de las restricciones en la siguiente lista es una que no desea. Pruebe esto: (1) mire cada restricción e intente averiguar cuál no espera; (2) encuentre el código que agregó la restricción o restricciones no deseadas y arréglelo. (Nota: Si está viendo NSAutoresizingMaskLayoutConstraints que no comprende, consulte la documentación de la propiedad UIView ) (

Por lo tanto, no estoy seguro de cómo solucionar esto todavía, pero no parece romper nada además de ser molesto.

alguien sabe como resolverlo? Curiosamente, las restricciones de diseño se etiquetan con bastante frecuencia con ''UISV-hiding'' , lo que indica que tal vez debería ignorar los mínimos de altura para las subvistas o algo en este caso.


Cuando configura una vista como oculta, la vista de UIStackview intentará animarla. Si desea ese efecto, deberá establecer la prioridad correcta para las restricciones para que no entren en conflicto (como muchos han sugerido anteriormente).

Sin embargo, si no le importa la animación (tal vez la está ocultando en ViewDidLoad), puede simplemente removeFromSuperview que tendrá el mismo efecto pero sin ningún problema con restricciones, ya que se eliminarán junto con la vista.


Es posible que haya creado una restricción mientras trabajaba con una determinada clase de tamaño (por ejemplo: wCompact hRegular) y luego creó un duplicado cuando cambió a otra clase de tamaño (por ejemplo: wAny hAny). verifique las restricciones de los objetos de la IU en diferentes clases de tamaño y vea si hay anomalías con las restricciones. debería ver las líneas rojas que indican restricciones de colisión. No puedo poner una foto hasta que obtenga 10 puntos de reputación lo siento: /


Estaba teniendo un problema similar que no fue fácil de resolver. En mi caso, tenía una vista de pila incrustada en una vista de pila. El UIStackView interno tenía dos etiquetas y se especificaba un espacio distinto de cero.

Cuando llame a addArrangedSubview (), creará automáticamente restricciones similares a las siguientes:

V:|[innerStackView]| | = outerStackView V:|[label1]-(2)-[label2]| | = innerStackView

Ahora, cuando intentas ocultar innerStackView, obtienes una advertencia de restricciones ambiguas.

Para entender por qué, primero veamos por qué esto no sucede cuando innerStackView.spacing es igual a 0 . Cuando llama a innerStackView.hidden = true , @liamnichols era correcto ... el outerStackView interceptará mágicamente esta llamada y creará una restricción de ocultación UISV de altura 0 con prioridad 1000 (obligatorio). Presumiblemente, esto es para permitir que los elementos en la vista de pila se animen fuera de la vista en caso de que su código oculto se UIView.animationWithDuration() dentro de un bloque UIView.animationWithDuration() . Desafortunadamente, no parece haber una manera de evitar que se agregue esta restricción. Sin embargo, no recibirá una advertencia "No se puede satisfacer simultáneamente las restricciones" (USSC), ya que ocurre lo siguiente:

  1. la altura de label1 se establece en 0
  2. el espacio entre las dos etiquetas ya estaba definido como 0
  3. la altura de label2 se establece en 0
  4. la altura de innerStackView se establece en 0

Está claro ver que esas 4 restricciones pueden cumplirse. La vista de pila simplemente suaviza todo en un píxel de altura 0.

Ahora volviendo al ejemplo con errores, si establecemos el spacing en 2 , ahora tenemos estas restricciones:

  1. la altura de label1 se establece en 0
  2. el espacio entre las dos etiquetas fue creado automáticamente por la vista de pila como 2 píxeles de alto con una prioridad de 1000.
  3. la altura de label2 se establece en 0
  4. la altura de innerStackView se establece en 0

La vista de pila no puede tener 0 píxeles de alto y su contenido puede tener 2 píxeles de alto. Las restricciones no pueden ser satisfechas.

Nota: Puede ver este comportamiento con un ejemplo más simple. Simplemente agregue una vista UIView a una vista de pila como una subvista organizada. Luego establezca una restricción de altura en esa UIView con 1000 prioridad. Ahora intenta llamar a hide en eso.

Nota: Por alguna razón, esto solo sucedió cuando mi vista de pila era una subvista de UICollectionViewCell o UITableViewCell. Sin embargo, aún puede reproducir este comportamiento fuera de una celda llamando a innerStackView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) en el siguiente ciclo de ejecución después de ocultar la vista de la pila interna.

Nota: Incluso si intenta ejecutar el código en un UIView.performWithoutAnimations, la vista de pila seguirá agregando una restricción de altura 0 que causará la advertencia de USSC.

Hay al menos 3 soluciones a este problema:

  1. Antes de ocultar cualquier elemento en una vista de pila, verifique si es una vista de pila, y si es así, cambie el spacing a 0. Esto es molesto porque necesita revertir el proceso (y recordar el espacio original) cada vez que muestre el contenido nuevamente.
  2. En lugar de ocultar elementos en una vista de pila, llame a removeFromSuperview . Esto es aún más molesto ya que cuando invierte el proceso, debe recordar dónde insertar el elemento eliminado. Puede optimizar solo llamando a removeArrangedSubview y luego ocultándose, pero todavía queda mucho por hacer.
  3. Ajustar vistas de pila anidadas (que tienen un spacing distinto de cero) en una UIView. Especifique al menos una restricción como prioridad no requerida (999 o inferior). Esta es la mejor solución ya que no tiene que hacer ningún tipo de contabilidad. En mi ejemplo, creé restricciones superiores, iniciales y finales en 1000 entre la vista de pila y la vista de contenedor, luego creé una restricción 999 desde la parte inferior de la vista de pila a la vista de contenedor. De esta manera, cuando la vista de la pila externa crea una restricción de altura cero, la restricción 999 se rompe y no se ve la advertencia del USSC. (Nota: Esto es similar a la solución de En caso de que contentView.translatesAutoResizingMaskToConstraints de una subclase UICollectionViewCell se establezca en false )

En resumen, las razones por las que obtiene este comportamiento son:

  1. Apple crea automáticamente 1000 restricciones de prioridad para usted cuando agrega subvistas administradas a una vista de pila.
  2. Apple crea automáticamente una restricción de altura 0 para usted cuando oculta una subvista de una vista de pila.

Si Apple (1) le hubiera permitido especificar la prioridad de las restricciones (especialmente de los espaciadores), o (2) le hubiera permitido optar por la restricción automática de ocultación de UISV , este problema se resolvería fácilmente.


Este error no tiene nada que ver con UIStackView. Ocurre cuando tienes restricciones de conflicto con las mismas prioridades. Por ejemplo, si tiene una restricción indica que el ancho de su vista es 100, y tiene otra restricción al mismo tiempo que indica que el ancho de la vista es el 25% de su contenedor. Obviamente hay dos restricciones en conflicto. La solución es eliminar uno de ellos.


Experimenté los mismos errores con las Vistas de pila incrustadas, aunque todo funcionó bien en tiempo de ejecución.

Resolví los errores de restricción ocultando primero todas las vistas de sub-pila (configurando isHidden = true ) antes de ocultar la vista de pila principal.

Hacer esto no tenía toda la complejidad de eliminar vistas suborganizadas, manteniendo un índice para cuando sea necesario volver a agregarlas.

Espero que esto ayude.


La mayoría de las veces, este error se puede resolver reduciendo la prioridad de las restricciones para eliminar conflictos.


NOP con [mySubView removeFromSuperview]. Espero que pueda ayudar a alguien :)


Obtiene este problema porque al configurar una subvista desde UIStackView como oculta, primero restringirá su altura a cero para animarla.

Recibía el siguiente error:

2015-10-01 11:45:13.732 <redacted>[64455:6368084] 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:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: ''|'':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5be508d0 V:|-(8)-[UISegmentedControl:0x7f7f5bec4180] (Names: ''|'':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5bdfbda0 ''UISV-hiding'' V:[UIView:0x7f7f5be69d30(0)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: ''|'':UIView:0x7f7f5be69d30 )> 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.

Lo que intentaba hacer era colocar una UIView dentro de mi UIStackView que contuviera un recuadro UISegmentedControl de 8 puntos en cada borde.

Cuando lo configuro como oculto, intentaría restringir la vista del contenedor a una altura cero, pero debido a que tengo un conjunto de restricciones de arriba a abajo, hubo un conflicto.

Para resolver el problema, cambié mi prioridad de restricciones superior e inferior de 8 puntos de 1000 a 999 para que la UISV-hiding pueda tener prioridad si es necesario.


Primero, como otros han sugerido, asegúrese de que las restricciones que puede controlar, es decir, no las restricciones inherentes a UIStackView estén establecidas en la prioridad 999 para que puedan anularse cuando la vista esté oculta.

Si aún experimenta el problema, es probable que el problema se deba al espacio en las StackViews ocultas. Mi solución fue agregar un UIView como espaciador y establecer el espaciado UIStackView en cero. Luego establezca las restricciones View.height o View.width (dependiendo de una pila vertical u horizontal) al espacio de StackView.

Luego, ajuste las prioridades de abrazo de contenido y resistencia de compresión de contenido de sus vistas recién agregadas. Es posible que también deba cambiar la distribución del StackView padre.

Todo lo anterior se puede hacer en Interface Builder. Además, es posible que deba ocultar / mostrar algunas de las vistas recientemente agregadas mediante programación para que no tenga espacios no deseados.


Quería ocultar UIStackView''s completos a la vez, pero recibía los mismos errores que el OP, esto me lo solucionó:

for(UIView *currentView in self.arrangedSubviews){ for(NSLayoutConstraint *currentConstraint in currentView.constraints){ [currentConstraint setPriority:999]; } }


Recientemente luché con errores de diseño automático al ocultar un UIStackView . En lugar de hacer un montón de pilas de libros y envoltorios en UIViews , opté por crear una salida para mi parentStackView y salidas para los niños que quiero ocultar / mostrar.

@IBOutlet weak var parentStackView: UIStackView! @IBOutlet var stackViewNumber1: UIStackView! @IBOutlet var stackViewNumber2: UIStackView!

En el guión gráfico, así es como se ve mi parentStack:

Tiene 4 hijos y cada uno de ellos tiene un montón de vistas de pila dentro de ellos. Cuando oculta una vista de pila, si tiene elementos de IU que también son vistas de pila, verá una secuencia de errores de diseño automático. En lugar de esconderme, opté por eliminarlos.

En mi ejemplo, parentStackViews contiene una matriz de los 4 elementos: Vista de pila superior, StackViewNumber1, Vista de pila número 2 y Botón de detención. Sus índices en subvistas arrangedSubviews son 0, 1, 2 y 3, respectivamente. Cuando quiero ocultar uno, simplemente lo parentStackView''s matriz arrangedSubviews de parentStackView''s de parentStackView''s . Como no es débil, permanece en la memoria y puede volver a colocarlo en su índice deseado más adelante. No lo estoy reiniciando, por lo que solo se cuelga hasta que se necesita, pero no hincha la memoria.

Entonces, básicamente, puedes ...

1) Arrastre IBOutlets para su pila principal y los hijos que desea ocultar / mostrar al guión gráfico.

2) Cuando desee ocultarlos, elimine la pila que desea ocultar de parentStackView''s matriz de parentStackView''s arrangedSubviews de parentStackView''s .

3) Llame a self.view.layoutIfNeeded() con UIView.animateWithDuration .

Tenga en cuenta que los dos últimos stackViews no son weak . Debe mantenerlos cerca para cuando los muestre.

Digamos que quiero ocultar stackViewNumber2:

parentStackView.removeArrangedSubview(stackViewNumber2) stackViewNumber2.removeFromSuperview()

Entonces animarlo:

UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil)

Si desea "mostrar" un stackViewNumber2 más tarde, puede insertarlo en el índice parentStackView deseado y animar la actualización.

parentStackView.removeArrangedSubview(stackViewNumber1) stackViewNumber1.removeFromSuperview() parentStackView.insertArrangedSubview(stackViewNumber2, at: 1) // Then animate it UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil)

Descubrí que eso es mucho más fácil que llevar la contabilidad de las restricciones, jugar con las prioridades, etc.

Si tiene algo que desea ocultar de forma predeterminada, puede colocarlo en el guión gráfico y eliminarlo en viewDidLoad y actualizar sin la animación usando view.layoutIfNeeded() .


Senseful ha proporcionado una excelente respuesta a la raíz del problema anterior, así que iré directamente a la solución.

Todo lo que necesita hacer es establecer todas las restricciones de stackView con prioridad inferior a 1000 (999 hará el trabajo). Por ejemplo, si stackView está restringido a la izquierda, a la derecha, a la parte superior e inferior de su supervista, entonces las 4 restricciones deberían tener una prioridad inferior a 1000.


Tenía una fila de botones con restricción de altura. Esto sucede cuando un botón está oculto. Establecer la prioridad de esa restricción de altura de botones en 999 ha resuelto el problema.