使用嵌套的 UIStackviews 隐藏 UIStackView

Hiding a UIStackView with nested UISTackviews

前言:我查看了 and it didn't solve my problem. Here's a link to a repo,其中显示了我遇到的错误。

我有一个 UIViewController,其中一个垂直 UIStackView 包含嵌套的水平 UIStackViews

有两个 UIStackViews 被切换。如果显示 UIStackViewNumber1,则隐藏 UIStackViewNumber2,反之亦然。本来我把视图设置成两者都显示,但是太挤了

UIStackView
    stackViewThatDoesntMove
    stackViewNumber1
    stackViewNumber2
    stackViewThatDoesntMove

如果我不隐藏任何内容,一切正常,不会出现 AutoLayout 错误。每个 UIStackViews 都有包含按钮、标签、滑块等的嵌套 stackViews。我发现视图太拥挤,所以我想我应该设置隐藏其中一个 stackViews 并设置动画变化,如下所示:

stackViewNumber2.isHidden = true

UIView.animate(withDuration: 0.33,
               options: [.curveEaseOut],
               animations: {
                self.stackViewNumber1.layoutIfNeeded()
                self.stackViewNumber2.layoutIfNeeded()
                self.view.layoutIfNeeded()
                    },
               completion: nil)
}

虽然我在模拟器和物理设备上获得了想要的结果,但当我隐藏其中一个 UIStackView 时,我的控制台充满了 AutoLayout 错误。

我看了一下 ,我的问题似乎很简单。我采用了最少 "bookkeeping" 的方法,并将 stackViewNumber2 包装在 UIView 中。我最终遇到了与最初相同的一组错误,但没有将 stackViewNumber1 包装在 UIView.

我也阅读了 Apple's documentation on UIStackView 并尝试使用 arrangedSubviews() 来设置约束 isActive = false,如下所示:

for subview in stackViewNumber2.arrangedSubviews {
    for constraint in subview.constraints {
        constraint.isActive = false
    }
}

stackViewNumber2.updateConstraints()
// then run animation block to update view

有没有更有效的隐藏嵌套 UIStackViews 的方法而不添加 IBOutlet 约束,确保它不弱,并记录 isActive 是否是 true/false?

我认为我的问题与嵌套的 stackViews 有关,但我不知道如何解决它。感谢您的阅读,欢迎就如何隐藏包含嵌套 UIStackViews.

UIStackView 提出建议

与其隐藏,我认为最好删除 stackView 本身。

myStackView.removeArrangedSubview(playButton)
playButton.removeFromSuperview()

希望对您有所帮助。

我开始想要动画隐藏一个视图并取消隐藏另一个视图,但是在 ,我尝试从超级视图中删除 stackViewNumber1 并将其替换为 stackViewNumber2。最终结果更清晰,簿记最少,无需将大量 @IBOutlets 拖到 viewController 上以更新约束等

parentStackView 的视图按照它们在 Main.storyboard 中显示的顺序存储在堆栈的 arrangedSubviews() 数组中。

在此示例中,arrangedSubviews 数组如下所示:

[topStackView, stackViewNumber1, stackViewNumber2, stopButton]

我只需要知道parentStackViewstackViewNumber1stackViewNumber2,所以我拖了3个outlets到storyboard,如下:

// StackViews the viewController needs to know about...
@IBOutlet weak var parentStackView: UIStackView!
// note weak is removed from the following 2 stackViews
@IBOutlet var stackViewNumber1: UIStackView!
@IBOutlet var stackViewNumber2: UIStackView!

从那里,如果我想删除 stackViewNumber2,以下代码将其删除:

parentStackView.removeArrangedSubview(stackViewNumber2)
// parentStackView.arrangedSubviews() = [topStackView, stackViewNumber1, stopButton]
stackViewNumber2.removeFromSuperview()
parentStackView.insertArrangedSubview(stackViewNumber1, at: 1)
// parentStackView.arrangedSubviews() = [topStackView, stackViewNumber1, stopButton]

现在,假设我想取出 stackViewNumber1 并将其替换为 stackViewNumber2:

parentStackView.removeArrangedSubview(stackViewNumber1)
// parentStackView.arrangedSubviews() = [topStackView, stopButton]
stackViewNumber2.removeFromSuperview()
parentStackView.insertArrangedSubview(stackViewNumber2, at: 1) 
// parentStackView.arrangedSubviews() = [topStackView, stackViewNumber2, stopButton]

回想一下 stackViewNumber1stackViewNumber2 不是 weak。原因是我想把它们留在身边,这样我就可以把它们换进换出。由于将 2 UIStackView 插座更改为 weak.

,我没有看到对内存使用有任何不利影响

最终结果:我在最初的方法中遇到的大量 AutoLayout 错误在没有大量簿记的情况下消失了。

更新:

稍加修改,我也可以使用动画了。这是代码:

    UIView.animate(withDuration: 0.25,
                   delay: 0,
                   usingSpringWithDamping: 2.0,
                   initialSpringVelocity: 10.0,
                   options: [.curveEaseOut],
                   animations: {
                    self.view.layoutIfNeeded()
    },
                   completion: nil)