【问题标题】:UIStackView Hide View AnimationUIStackView 隐藏视图动画
【发布时间】: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 上恢复之前的行为?

【问题讨论】:

    标签: ios swift animation uikit uistackview


    【解决方案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 的 subviewhidden 属性会被忽略,所以最好的方法是在动画之前将其更改为外部。
    • 可能是我的一个误解,但从文档中听起来,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 并将视图隐藏在完成块中之前,这都是一团糟。谢谢冠军!
    猜你喜欢
    • 2019-05-31
    • 1970-01-01
    • 2021-06-01
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-31
    相关资源
    最近更新 更多