UIStackView: problemas de restricciones de layout cuando se ocultan vistas de stack

Mi aplicación tiene 2 pantallas:

  1. TableViewVC (no hay vistas de stack aquí)

  2. DetailVC (todas las vistas de la stack anidada aquí; consulte el enlace de la image: Imagen de la StackViews anidada ) – Tenga en count que hay tags e imágenes dentro de estas vistas de la stack.

Cuando presiona una celda en la vista de tabla, pasa la información de TableViewVC a DetailVC. El problema es ocultar los UIStackViews específicos en DetailVC. Quiero que se oculten solo 2 vistas de la stack de las varias en DetailVC tan pronto como se cargue la vista. Entonces escribo este código en DetailVC para lograr esto:

override func viewDidLoad() { super.viewDidLoad() self.nameLabel.text = "John" self.summaryStackView.hidden = true self.combinedStackView.hidden = true } 

Todo se ve muy bien, pero Xcode da muchas advertencias solo en time de ejecución . No hay advertencia en Storyboard cuando la aplicación no se está ejecutando. Consulte el enlace para get una image de los errores: Imagen de los errores.

Básicamente es una gran cantidad de UISV-hiding, UISV-spacing, UISV-canvas-connection errors. Estos errores desaparecen si viewDidAppear las mismas vistas de stack en viewDidAppear pero luego hay un flash de las cosas que se suponía que estaban ocultas y luego se esconde. El usuario ve la vista brevemente y luego se esconde, lo que no es bueno.

Perdón por no poder publicar imágenes en lugar de enlaces, pero no puedo hacerlo.

Alguna sugerencia en como arreglar esto? Esto es para una aplicación que realmente quiero lanzar a la tienda de aplicaciones: ¡es mi primera vez, así que cualquier ayuda sería genial!

Editar / Actualizar 1:

Encontré un pequeño trabajo con este código que puse dentro de la segunda pantalla llamada DetailVC:

 // Function I use to delay hiding of views func delay(delay: Double, closure: ()->()) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), closure) } // Hide the 2 stack views after 0.0001 seconds of screen loading override func awakeFromNib() { delay(0.001) { () -> () in self.summaryStackView.hidden = true self.combinedStackView.hidden = true } } // Update view screen elements after 0.1 seconds in viewWillAppear override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) delay(0.1) { () -> () in self.nameLabel.text = "John" } } 

Esto elimina las advertencias sobre las restricciones de layout completamente de Xcode.

Todavía no es perfecto porque a veces veo un vistazo de las vistas que se supone que están ocultas: parpadean rápidamente en la pantalla y luego desaparecen. Sin embargo, esto sucede muy rápido.

¿Alguna sugerencia sobre por qué esto elimina las advertencias? Además, ¿alguna sugerencia sobre cómo mejorar esto funciona perfectamente? ¡Gracias!

¿Has probado esto, llamando al súper después de tus cambios?

 override func viewWillAppear() { self.nameLabel.text = "John" self.summaryStackView.hidden = true self.combinedStackView.hidden = true super.viewWillAppear() } 

Tuve el mismo problema y lo solucioné dando a las restricciones de altura de mis vistas ocultas inicialmente una prioridad de 999.

introduzca la descripción de la imagen aquí

El problema es que su stackview aplica una restricción de altura de 0 en su vista oculta que entra en conflicto con su otra restricción de altura. Este fue el post de error:

 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:0x7fa3a5004310 V:[App.DummyView:0x7fa3a5003fd0(40)]>", "<NSLayoutConstraint:0x7fa3a3e44190 'UISV-hiding' V:[App.DummyView:0x7fa3a5003fd0(0)]>" ) 

Darle a su restricción de altura una prioridad más baja resuelve este problema.

Este es un problema conocido para ocultar vistas de stack anidadas.

Existen esencialmente 3 soluciones a este problema:

  1. Cambie el espaciado a 0, pero luego tendrá que recordar el valor de espaciado anterior.
  2. Llame a innerStackView.removeFromSuperview() , pero luego deberá recordar dónde insert la vista de stack.
  3. Ajustar la vista de la stack en una UIView con al less una restricción de 999. Por ejemplo, Top, Leading, Trailing @ 1000, Bottom @ 999.

La tercera opción es la mejor en mi opinión. Para get más información sobre este problema, por qué sucede, las diferentes soluciones y cómo implementar la solución 3, vea mi respuesta a una pregunta similar .

Puede usar la propiedad removeArrangedSubview y removeFromSuperview de UIStackView.

En Objective-C:

  [self.topStackView removeArrangedSubview:self.summaryStackView]; [self.summaryStackView removeFromSuperview]; [self.topStackView removeArrangedSubview:self.combinedStackView]; [self.combinedStackView removeFromSuperview]; 

Desde la documentation de Apple UIStackView 🙁 https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIStackView_Class_Reference/#//apple_ref/occ/instm/UIStackView/removeArrangedSubview 🙂

La vista de stack actualiza automáticamente su layout cada vez que se agregan, eliminan o insertan vistas en la matriz arrangedSubviews.

  • removeArrangedSubview: este método elimina la vista provista de la matriz arrangedSubviews de la stack. La position y el tamaño de la vista ya no serán gestionados por la vista de stack. Sin embargo, este método no elimina la vista provista de la matriz de subvenciones de la stack; por lo tanto, la vista aún se muestra como parte de la jerarquía de vista.

Para evitar que la vista aparezca en pantalla después de llamar al método removeArrangedSubview: remove de forma explícita la vista de la matriz de subestaciones llamando al método removeFromSuperview de la vista, o establezca la propiedad oculta de la vista en YES.

Moví todo el código UIStackView.hidden de viewDidLoad para verDidAppear y el problema de restricciones rotas desapareció. En mi caso, todas las restricciones conflictivas se generaron automáticamente, así que no hay manera de ajustar las prioridades.

También utilicé este código para hacerlo más bonito:

 UIView.animateWithDuration(0.5) { self.deliveryGroup.hidden = self.shipVia != "1" } 

EDITAR:

También se necesita el siguiente código para evitar que vuelva a ocurrir cuando el dispositivo gira:

 override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) self.deliveryGroup.hidden = false coordinator.animateAlongsideTransition(nil) { context in self.deliveryGroup.hidden = self.shipVia != "1" } } 

Lo arreglé poniendo los commands hide en traitCollectionDidChange.

 override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) self.item.hidden = true } 

Cuando se oculta el UIViewStack, las restricciones generadas automáticamente por el UIStackView arrojarán muchas advertencias UISV-hiding, UISV-space, UISV-canvas-connection, si la propiedad de espaciamiento de UIStackView tiene un valor distinto de cero.

Esto no tiene mucho sentido, es casi seguro que es un error de marco. La solución provisional que utilizo es establecer el espacio a cero al ocultar el componente.

 if hideStackView { myStackView.hidden = true myStackView.spacing = CGFloat(0) } else { myStackView.hidden = false myStackView.spacing = CGFloat(8) } 

Pon tus commands hide en viewWillLayoutSubviews() {}

Este error no se trata de ocultar, sino de restricciones ambiguas. No debe tener restricciones ambiguas en su vista. Si los agrega mediante progtwigción, debe comprender exactamente qué restricciones agrega y cómo funcionan juntas. Si no los agrega mediante progtwigción, pero use storyboard o xib, que es un buen lugar para comenzar, asegúrese de que no haya errores de restricción ni advertencias.

UPD: tiene una estructura bastante compleja de vistas allí. Sin ver las restricciones es difícil decir qué es exactamente lo que está mal. Sin embargo, sugeriría que comstackra la jerarquía de vistas añadiendo gradualmente vistas una por una y asegurándose de que no hay advertencias de time de layout / time de ejecución. La vista de desplazamiento puede agregar otro nivel de complejidad si no lo maneja correctamente. Descubra cómo usar restricciones con una vista de desplazamiento. El rest de los hacks de synchronization no es una solución de todos modos.

He encontrado que UIStackViews nesteds muestran este comportamiento si configura la propiedad oculta en ✨Interface Builder✨. Mi solución fue configurar todo para que no esté oculto en ✨Interface Builder✨, y oculta las cosas en la vista de forma selectiva.