通过动作无约束地动画扩展子视图

animated expanding of subview by action without constraints

我有一个带有 UIScrollView 作为子视图的 UIViewController。滚动视图大小和原点是计算属性。

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        
        let sizeWidth = view.frame.size.width - (view.frame.size.width / 5)
        let sizeHeight = (view.frame.height / 5) * 3
        let originX = (view.width-sizeWidth) / 2
        
        // sizes & positions of container & subviews
        slideScrollView.frame = CGRect(x: originX,
                                      y: 50,
                                      width: sizeWidth,
                                      height: sizeHeight)

how it looks like

通过点击登录或登录按钮,滚动视图应该展开动画。但恰恰相反

@objc private func loginButtonTapped() {
        UIView.animate(withDuration: 5, delay: 0, options: .allowAnimatedContent) {
            self.slideScrollView.frame.size.height += (self.view.frame.height / 5) * 1
        }
    }

this is the result

它应该展开,但它设置回动作高度 属性 并展开为常规大小, 我希望任何人都可以告诉我为什么会发生这种情况并且可能有解决方案。

那是因为当您使用 UIView.animate(withDuration: 开始动画时,您的 viewDidLayoutSubviews 被多次调用(在这种情况下,我通过添加调试语句注意到了两次)并且因为您总是重置 slideScrollView.frameviewDidLayoutSubviews 你看到了不必要的副作用。

loginButtonTapped 被触发时,您总是可以通过在 viewDidLayoutSubviews 中放置一个断点来检查这一点。请参阅此 以获得类似的解释

如果您打算使用 viewDidLayoutSubviews 来了解何时正确加载视图以及正确更新其框架,您可以随时使用

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let sizeWidth = view.frame.size.width - (view.frame.size.width / 5)
        let sizeHeight = (view.frame.height / 5) * 3
        let originX = (view.width-sizeWidth) / 2
        
        // sizes & positions of container & subviews
        slideScrollView.frame = CGRect(x: originX,
                                      y: 50,
                                      width: sizeWidth,
                                      height: sizeHeight)
    }

现在您的 loginButtonTapped 应该可以正常工作了。

根据 apple docsviewDidLayoutSubviews 调用以通知视图控制器它的视图刚刚布置了它的子视图。

我认为我上面的解释是有道理的,你使用 UIView.animate(withDuration: 修改 scrollView 的框架,所以很明显 View updates/re-renders 子视图因此 viewDidLayoutSubviews 被调用当您调用 UIView.animate(withDuration: 并且由于 viewDidLayoutSubviews 中的帧更新代码,您会看到不利的副作用