En iOS 11, el comportamiento de la animación oculta dentro de a UIStackView
ha cambiado, pero no he podido encontrar esto documentado en ninguna parte.
iOS 10
iOS 11
El código en ambos es este:
UIView.animate(withDuration: DiscoverHeaderView.animationDuration,
delay: 0.0,
usingSpringWithDamping: 0.9,
initialSpringVelocity: 1,
options: [],
animations: {
clear.isHidden = hideClear
useMyLocation.isHidden = hideLocation
},
completion: nil)
¿Cómo restauro el comportamiento anterior en iOS 11?
hidden
propiedad de unUIStackView
'ssubview
en el bloque de animación estaba siendo ignorado en algunos casos, por lo que la mejor manera es cambiar fuera de ella, justo antes de la animación.view.layoutIfNeeded()
actualicen la posición de otras vistas en StackView, que es lo que queremos. developer.apple.com/documentation/uikit/uiview/…Extensión Swift 4:
// MARK: - Show hide animations in StackViews extension UIView { func hideAnimated(in stackView: UIStackView) { if !self.isHidden { UIView.animate( withDuration: 0.35, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 1, options: [], animations: { self.isHidden = true stackView.layoutIfNeeded() }, completion: nil ) } } func showAnimated(in stackView: UIStackView) { if self.isHidden { UIView.animate( withDuration: 0.35, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 1, options: [], animations: { self.isHidden = false stackView.layoutIfNeeded() }, completion: nil ) } } }
fuente
self.isHidden
y no establecer el valor si ya es el mismo.Ya se menciona en los comentarios de la respuesta aceptada, pero este era mi problema y no está en ninguna de las respuestas aquí, así que:
Asegúrese de no establecer nunca
isHidden = true
una vista que ya esté oculta. Esto estropeará la vista de la pila.fuente
layoutIfNeeded
así que me pregunto si esta debería ser la respuesta correcta.Quiero compartir esta función que es buena para ocultar y mostrar muchas vistas
UIStackView
, porque con todo el código que usé antes no funcionó bien porque es necesario eliminar la animación de algunas capas:extension UIStackView { public func make(viewsHidden: [UIView], viewsVisible: [UIView], animated: Bool) { let viewsHidden = viewsHidden.filter({ $0.superview === self }) let viewsVisible = viewsVisible.filter({ $0.superview === self }) let blockToSetVisibility: ([UIView], _ hidden: Bool) -> Void = { views, hidden in views.forEach({ $0.isHidden = hidden }) } // need for smooth animation let blockToSetAlphaForSubviewsOf: ([UIView], _ alpha: CGFloat) -> Void = { views, alpha in views.forEach({ view in view.subviews.forEach({ $0.alpha = alpha }) }) } if !animated { blockToSetVisibility(viewsHidden, true) blockToSetVisibility(viewsVisible, false) blockToSetAlphaForSubviewsOf(viewsHidden, 1) blockToSetAlphaForSubviewsOf(viewsVisible, 1) } else { // update hidden values of all views // without that animation doesn't go let allViews = viewsHidden + viewsVisible self.layer.removeAllAnimations() allViews.forEach { view in let oldHiddenValue = view.isHidden view.layer.removeAllAnimations() view.layer.isHidden = oldHiddenValue } UIView.animate(withDuration: 0.3, delay: 0.0, usingSpringWithDamping: 0.9, initialSpringVelocity: 1, options: [], animations: { blockToSetAlphaForSubviewsOf(viewsVisible, 1) blockToSetAlphaForSubviewsOf(viewsHidden, 0) blockToSetVisibility(viewsHidden, true) blockToSetVisibility(viewsVisible, false) self.layoutIfNeeded() }, completion: nil) } } }
fuente
Extensión para ocultar / mostrar elementos individuales
No está 100% relacionado, pero si está buscando una forma concisa de ocultar
UIView
los elementos individuales (ya sea en una vista de pila o en cualquier otro lugar), puede usar esta extensión simple que hice:extension UIView { func isHiddenAnimated(value: Bool, duration: Double = 0.2) { UIView.animate(withDuration: duration) { [weak self] in self?.isHidden = value } } }
Lo uso para ocultar / mostrar convenientemente elementos con animación en una vista de pila con una sola línea de código. Ejemplo:
validatableButton.isHiddenAnimated(value: false)
fuente
Espero que esto les ahorre a otros algunas horas de frustración.
Animar la ocultación Y mostrar varias subvistas de UIStackView al mismo tiempo es un desastre.
En algunos casos, los cambios .isHidden en los bloques de animación se muestran correctamente hasta la siguiente animación, luego .isHidden se ignora. El único truco confiable que encontré para esto es repetir las instrucciones .isHidden en la sección de finalización del bloque de animación.
let time = 0.3 UIView.animate(withDuration: time, animations: { //shows self.googleSignInView.isHidden = false self.googleSignInView.alpha = 1 self.registerView.isHidden = false self.registerView.alpha = 1 //hides self.usernameView.isHidden = true self.usernameView.alpha = 0 self.passwordView.isHidden = true self.passwordView.alpha = 0 self.stackView.layoutIfNeeded() }) { (finished) in self.googleSignInView.isHidden = false self.registerView.isHidden = false self.usernameView.isHidden = true self.passwordView.isHidden = true }
fuente