IOS 11では、UIStackView
内のアニメーションの非表示の動作が変更されましたが、このドキュメントはどこにも見つかりませんでした。
iOS 10
iOS 11
両方のコードは次のとおりです。
UIView.animate(withDuration: DiscoverHeaderView.animationDuration,
delay: 0.0,
usingSpringWithDamping: 0.9,
initialSpringVelocity: 1,
options: [],
animations: {
clear.isHidden = hideClear
useMyLocation.isHidden = hideLocation
},
completion: nil)
IOS 11で以前の動作を復元するにはどうすればよいですか?
ちょうど同じ問題がありました。修正は、アニメーションブロック内にstackView.layoutIfNeeded()
を追加することです。ここで、stackView
は、非表示にするアイテムのコンテナです。
UIView.animate(withDuration: DiscoverHeaderView.animationDuration,
delay: 0.0,
usingSpringWithDamping: 0.9,
initialSpringVelocity: 1,
options: [],
animations: {
clear.isHidden = hideClear
useMyLocation.isHidden = hideLocation
stackView.layoutIfNeeded()
},
completion: nil)
これが突然iOS 11で問題になる理由は定かではありませんが、公平を期すために、常に推奨されるアプローチでした。
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
)
}
}
}
UIStackView
で多くのビューを非表示にして表示するのに適したこの関数を共有したいのは、以前に使用したすべてのコードがいくつかのレイヤーからアニメーションを削除する必要があるためにスムーズに動作しなかったためです:
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)
}
}
}