iOS 11 UIStackView 填充按比例分布导致奇怪的视图加载动画

Posted

技术标签:

【中文标题】iOS 11 UIStackView 填充按比例分布导致奇怪的视图加载动画【英文标题】:iOS 11 UIStackView fill proportionally distribution causes weird view loading animation 【发布时间】:2017-08-25 12:12:39 【问题描述】:

如果我设置:

stackView.distributon = .fillProportionally 

然后在 ios 11 上,当加载包含此堆栈视图的视图时,我得到一个非常奇怪的动画(所有子视图 - 不仅仅是堆栈视图 - 都从屏幕的顶部或底部飞出)。在较低的 iOS 版本上一切正常。如果我将堆栈视图的分布设置为其他任何内容,那么一切正常。

有谁知道这个问题可能是什么原因造成的?

谢谢。

【问题讨论】:

您找到解决方案了吗?我对从屏幕顶部飞来的视图有类似的问题 - 尽管我的堆栈视图设置为 Fill 分布(默认值)。使用 Xcode 9 GM 种子和 iOS 11 GM 种子。 在设置 stackView.distributon = .fillProportionally 之前调用 self.view.layoutIfNeeded() 有帮助。 @MattCline 我也有同样的问题...... :(。知道如何解决它吗? 【参考方案1】:

我想我找到了解决办法 - 在 animations 块中调用 self.view.layoutIfNeeded()

这是我的复制品:

import UIKit

class ViewController: UIViewController 

    var showB = true

    weak var viewB: UIView!

    override func viewDidLoad() 
        super.viewDidLoad()

        let viewA = UIView()
        viewA.backgroundColor = UIColor.green

        let toggleViewBButtonAnimated = UIButton(frame: CGRect(x: 50, y: 150, width: 200, height: 40))
        toggleViewBButtonAnimated.backgroundColor = UIColor.cyan
        toggleViewBButtonAnimated.setTitle("Toggle B (animated)", for: .normal)
        viewA.addSubview(toggleViewBButtonAnimated)
        toggleViewBButtonAnimated.addTarget(self, action: #selector(toggleBButtonTappedAnimated), for: .touchUpInside)


        let viewB = UIView()
        viewB.backgroundColor = UIColor.orange
        let viewBHeightConstraint = viewB.heightAnchor.constraint(equalToConstant: 200)
        viewBHeightConstraint.priority = 999
        viewBHeightConstraint.isActive = true
        self.viewB = viewB


        let stackView = UIStackView(arrangedSubviews: [viewA, viewB])
        stackView.axis = .vertical
        stackView.alignment = .fill
        stackView.distribution = .fill
        stackView.translatesAutoresizingMaskIntoConstraints = false

        self.view.addSubview(stackView)

        stackView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
    

    @IBAction func toggleBButtonTappedAnimated() 
        self.showB = !self.showB
        UIView.animate(withDuration: 0.3,
                       animations:  self.viewB.isHidden = !self.showB; self.view.layoutIfNeeded() 
        )
    

这个控制器设置了一个UIStackView,它有两个垂直视图,一个绿色(A)和一个橙色(B)。点击按钮隐藏/取消隐藏视图 B。

如果我没有animations 块中有self.view.layoutIfNeeded(),那么,当显示视图B 时,它会从屏幕顶部飞入。 (当视图 B 被隐藏时,它会正常隐藏 - 从屏幕底部向下移动。)

当我将 self.view.layoutIfNeeded() 添加到 animations 块时,视图 B 显示为预期 - 它从屏幕底部出现。

感谢@g3rv4 的回答为我指明了这个方向!

【讨论】:

太棒了!在设置stackView.distributon = .fillProportionally 之前调用self.view.layoutIfNeeded() 有帮助!谢谢。 您不应该在动画块中更改 UIStackViewsubview 的 hidden 属性,因为 iOS 将 self.view.layoutIfNeeded() 添加到动画块的末尾为我修复了它。 stackview 以前是从屏幕顶部动画的,但不是从正确的点动画。谢谢!【参考方案2】:

对我来说,问题是 iOS 11 中引入的行为回归,与 UIStackView 分发类型无关。我尝试了几个基于代码的解决方案都无济于事:首先,在容器层次结构上调用 layoutIfNeeded;其次,(如在另一个类似问题的答案中所见)调整视图的 contentMode。

我的 hacky 解决方案如下:

在 UIStackView 的一侧添加一个新的零宽度 UIView 占位符,其中显示动画错误地将项目从屏幕边缘带入。

【讨论】:

太棒了。它只是工作。我将在余生中思考你是如何想出这个解决方案的 :) Saint-Steve 一定启发了你。【参考方案3】:

今天早上我在使用 GM 种子时遇到了同样的问题。我最终使用了UIView.performWithoutAnimation 块来对暂时不需要动画的UIStackView 进行任何修改。

【讨论】:

以上是关于iOS 11 UIStackView 填充按比例分布导致奇怪的视图加载动画的主要内容,如果未能解决你的问题,请参考以下文章

使用乘数在 UIStackView 内按比例设置视图 - 快速 - 以编程方式

替换 UIStackView 中的视图

UIStackView 中按钮的按比例调整大小

如何使用 UIStackView 按比例调整大小?

UIStackView背景色和自定义间距

如何根据内容动态制作 Swift UIStackView 大小?