In iOS 11 hat sich das Verhalten der Hide-Animation in a UIStackView
geändert, aber ich konnte dies nirgendwo dokumentiert finden.
iOS 10
iOS 11
Der Code in beiden ist folgender:
UIView.animate(withDuration: DiscoverHeaderView.animationDuration,
delay: 0.0,
usingSpringWithDamping: 0.9,
initialSpringVelocity: 1,
options: [],
animations: {
clear.isHidden = hideClear
useMyLocation.isHidden = hideLocation
},
completion: nil)
Wie kann ich das vorherige Verhalten unter iOS 11 wiederherstellen?
hidden
Eigenschaft einesUIStackView
‚ssubview
in der Animation Block wurde in einigen Fällen ignoriert wird, so dass der beste Weg , um es außerhalb davon zu ändern , ist, kurz vor der Animation.view.layoutIfNeeded()
würde es die Position anderer Ansichten in der StackView aktualisieren, was wir wollen. developer.apple.com/documentation/uikit/uiview/…Swift 4-Erweiterung:
// 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 ) } } }
quelle
self.isHidden
den Wert zu überprüfen und nicht festzulegen, wenn er bereits gleich ist.Es ist bereits in den Kommentaren der akzeptierten Antwort erwähnt, aber dies war mein Problem und es ist in keiner der Antworten hier so:
Stellen Sie sicher, dass Sie niemals
isHidden = true
eine Ansicht festlegen , die bereits ausgeblendet ist. Dies wird die Stapelansicht durcheinander bringen.quelle
layoutIfNeeded
also frage ich mich, ob dies die richtige Antwort sein sollte.Ich möchte diese Funktion teilen, die sich gut zum Ausblenden und Anzeigen vieler Ansichten eignet
UIStackView
, da der gesamte zuvor verwendete Code nicht reibungslos funktioniert hat, da Animation aus einigen Ebenen entfernt werden muss: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) } } }
quelle
Erweiterung zum Ausblenden / Anzeigen einzelner Elemente
Es ist nicht zu 100% verwandt, aber wenn Sie nach einer präzisen Möglichkeit suchen, einzelne
UIView
Elemente auszublenden (entweder in einer Stapelansicht oder irgendwo anders), können Sie diese einfache Erweiterung verwenden, die ich erstellt habe:extension UIView { func isHiddenAnimated(value: Bool, duration: Double = 0.2) { UIView.animate(withDuration: duration) { [weak self] in self?.isHidden = value } } }
Ich verwende es, um Elemente mit Animation in einer Stapelansicht mit einer einzelnen Codezeile bequem auszublenden / anzuzeigen. Beispiel:
validatableButton.isHiddenAnimated(value: false)
quelle
Hoffe, das erspart anderen ein paar Stunden Frust.
Das gleichzeitige Ausblenden UND Anzeigen mehrerer UIStackView-Unteransichten zu animieren, ist ein Chaos.
In einigen Fällen werden die .isHidden-Änderungen in den Animationsblöcken bis zur nächsten Animation korrekt angezeigt. Dann wird .isHidden ignoriert. Der einzige zuverlässige Trick, den ich dafür gefunden habe, besteht darin, die .isHidden-Anweisungen im Abschlussabschnitt des Animationsblocks zu wiederholen.
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 }
quelle