UIStackView隐藏视图动画

Inf*_*mes 53 animation uikit ios swift uistackview

在iOS 11中,隐藏动画在a中的行为UIStackView已发生变化,但我无法在任何地方找到此文档.

iOS 10

iOS 10动画

iOS 11

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)
Run Code Online (Sandbox Code Playgroud)

如何在iOS 11上恢复以前的行为?

Spr*_*ham 94

刚刚遇到同样的问题.修复是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)
Run Code Online (Sandbox Code Playgroud)

不知道为什么这在iOS 11中突然出现问题,但公平地说它始终是推荐的方法.

  • view.layoutIfNeeded() 是可以的,但是如果视图已经隐藏(或相反),则调用 view.isHidden = true 会破坏事情。因此,请务必检查视图是否已经是您要更改的隐藏状态。if(view.isHidden == true) { view.isHidden = false } (10认同)
  • 在 iOS <= 10 中,存在一个错误,在某些情况下,在动画块中设置“UIStackView”的“subview”的“hidden”属性会被忽略,因此最好的方法是在它之外更改它,就在动画之前。 (4认同)
  • 适当的名字以及'Springham' (2认同)
  • 可能是我的一个误解,但它听起来像`view.layoutIfNeeded()`这样的文档会更新StackView中其他视图的位置,这就是我们想要的.https://developer.apple.com/documentation/uikit/uiview/1622507-layoutifneeded (2认同)

jim*_*pic 20

它已经在接受的答案的评论中提到,但这是我的问题,它不在此处的任何答案中,所以:

确保永远不要isHidden = true在已经隐藏的视图上设置。这会弄乱堆栈视图。

  • 天哪,你是怎么找到的!救了我!❤️ (5认同)

Mat*_*jan 8

希望这可以帮助其他人避免几个小时的沮丧。

同时隐藏和显示多个 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
    }
Run Code Online (Sandbox Code Playgroud)


erg*_*cak 6

斯威夫特 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
        )
    }
}
}
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,修复方法是检查 `self.isHidden`,如果 is 已经相同,则不设置值。 (5认同)

Pau*_* T. 5

我想分享这个功能,它非常适合在 中隐藏和显示许多视图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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)