UIStackView 隐藏视图动画
Posted
技术标签:
【中文标题】UIStackView 隐藏视图动画【英文标题】:UIStackView Hide View Animation 【发布时间】:2018-03-01 18:22:28 【问题描述】:在 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 上恢复之前的行为?
【问题讨论】:
【参考方案1】:刚刚遇到同样的问题。
修复是在动画块内添加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 中突然成为一个问题,但公平地说,它一直是推荐的方法。
【讨论】:
你是英雄:D 合适的名字以及'Springham'? 在 iOS UIStackView 的subview
的 hidden
属性会被忽略,所以最好的方法是在动画之前将其更改为外部。
可能是我的一个误解,但从文档中听起来,view.layoutIfNeeded()
不会更新我们想要的 StackView 中其他视图的位置。 developer.apple.com/documentation/uikit/uiview/…
view.layoutIfNeeded() 没问题,但是如果视图已经隐藏(或相反),则调用 view.isHidden = true 会破坏事情。因此,请务必检查视图是否还不是您要更改的隐藏状态。 if(view.isHidden == true) view.isHidden = false 【参考方案2】:
已在接受答案的 cmets 中提到,但这是我的问题,它不在此处的任何答案中,所以:
确保从不在已经隐藏的视图上设置isHidden = true
。这会弄乱堆栈视图。
【讨论】:
这是我的问题,我不需要打电话给layoutIfNeeded
,所以我想知道这是否应该是正确的答案。
这对我来说是正确的答案。在不了解原因的情况下,我花了一整天的时间调试。一个简单的代码块就可以完成这项工作if self.isHidden != shouldHideView self.isHidden = shouldHideView
天哪,你是怎么找到的!救了我! ❤️【参考方案3】:
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
)
【讨论】:
对我来说,解决方法是检查self.isHidden
,如果已经相同则不设置值。
这很容易成为 1 个名为 toggleAnimated(in... , show: Bool) 的函数。因为只有一行更改:) 加上它对我不起作用:s
是的,制作单个函数后,2个函数将成为语法糖【参考方案4】:
我想分享这个功能,它有利于在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)
【讨论】:
这也解决了视图不淡入淡出的问题。漂亮!【参考方案5】:希望这可以为其他人节省几个小时的挫败感。
动画隐藏和同时显示多个 UIStackView 子视图是一团糟。
在某些情况下,动画块中的 .isHidden 更改会正确显示,直到下一个动画,然后 .isHidden 被忽略。我为此找到的唯一可靠技巧是在动画块的完成部分重复 .isHidden 指令。
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
【讨论】:
这是真的!直到我在动画期间更改了 alpha 并将视图隐藏在完成块中之前,这都是一团糟。谢谢冠军!以上是关于UIStackView 隐藏视图动画的主要内容,如果未能解决你的问题,请参考以下文章
在 iOS 9 上更改隐藏属性时 UIStackView 不会动画