gpt4 book ai didi

swift - UIStackView 动画问题

转载 作者:搜寻专家 更新时间:2023-11-01 06:57:18 27 4
gpt4 key购买 nike

我在 stackView 中有一个 subStackView,当我隐藏/显示一个 subStackView 的内容时,动画会一直向上移动到其他堆栈 View 上:https://www.youtube.com/watch?v=vKXwX7OpkxU

这就是我创建 subStackView 的方式。我尝试使用和不使用 clipToBounds 以及不使用 translatedAutoresizingMaskIntoConstraints。还在动画部分尝试了layoutIfNeeded。

let subStackView = UIStackView(arrangedSubviews: [self.innerView[0], self.innerView[1])
subStackView.translatesAutoresizingMaskIntoConstraints = false
subStackView.axis = .vertical
subStackView.distribution = .fillEqually
subStackView.alignment = .fill
subStackView.spacing = 0
subStackView.clipsToBounds = true

然后将此 subStackView 加载到导致问题的 mainStackView 中。

最佳答案

解决问题的一种方法是更直接地控制紫色 View 的显示和隐藏方式。您现在正在做的(我假设)是将 isHidden 属性设置为 true,然后让堆栈 View 做任何它想做的事情。相反,让我们将紫色 View 放在容器 View 中,并将容器 View 的高度动画化为零。然后它看起来像这样:

demo

使用容器 View 而不是直接为紫色 View 的高度设置动画的原因是您可能(通常)有其他约束来控制紫色 View 的高度,因此将其高度限制为零会使您的控制台充满无法满足的内容约束错误。

这就是我为演示所做的。我做了一个“你好,世界!”带有紫色背景的标签。我将其高度限制为 80。我将标签放在容器 View 中(只是一个普通的 UIView)。我像往常一样将标签的顶部、前导和尾部边缘限制在容器 View 中。我还将标签的底部边缘限制在容器 View 中,但优先级为 999*(低于默认的“必需”优先级 1000)。这意味着容器 View 将非常努力地尝试与标签的大小相同,但如果容器 View 被迫更改高度,它会在不影响标签高度的情况下这样做。

容器还设置了clipsToBounds,因此如果容器变得比标签短,标签的底部就会被隐藏。

为了切换标签的可见性,我在将高度设置为零的容器 View 上激活或停用了一个必需的优先级高度约束。然后我要求窗口在动画 block 内布置其子项。

在我的演示中,我还将堆栈 View 的 spacing 设置为 12。如果我只是让容器 View “可见”(不是 isHidden),高度为零,堆栈 View 将在按钮后放置 12 点的空间,这看起来不正确。在 iOS 11 及更高版本上,我通过在“隐藏”容器时将按钮后的自定义间距设置为 0 来解决此问题,并在“显示”容器时恢复默认间距。

在 iOS 11 之前的 iOS 版本上,我只是继续在隐藏动画完成后真正隐藏容器(将其 isHidden 设置为 true)。在运行显示动画之前,我显示容器(将其 isHidden 设置为 false)。当间距立即消失或重新出现时,这会导致一点点凸起,但这还算不错。

处理堆栈 View 间距会使代码变得更大,因此如果您不在堆栈 View 中使用间距,则可以使用更简单的代码。

无论如何,这是我的代码:

class TaskletViewController: UIViewController {

@IBAction func buttonWasTapped() {
if detailContainerHideConstraint == nil {
detailContainerHideConstraint = detailContainer.heightAnchor.constraint(equalToConstant: 0)
}
let wantHidden = !(detailContainerHideConstraint?.isActive ?? false)

if wantHidden {
UIView.animate(withDuration: 0.25, animations: {
if #available(iOS 11.0, *) {
self.stackView.setCustomSpacing(0, after: self.button)
}
self.detailContainerHideConstraint?.isActive = true
self.view.window?.layoutIfNeeded()
}, completion: { _ in
if #available(iOS 11.0, *) { } else {
self.detailContainer.isHidden = true
}
})
} else {
if #available(iOS 11.0, *) { } else {
detailContainer.isHidden = false
}
UIView.animate(withDuration: 0.25, animations: {
if #available(iOS 11.0, *) {
self.stackView.setCustomSpacing(self.stackView.spacing, after: self.button)
}
self.detailContainerHideConstraint?.isActive = false
self.view.window?.layoutIfNeeded()
})
}
}

override func loadView() {
stackView.axis = .vertical
stackView.spacing = 12
stackView.translatesAutoresizingMaskIntoConstraints = false

button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = UIColor.green.withAlphaComponent(0.2)
button.setTitle("Tap to toggle", for: .normal)
button.addTarget(self, action: #selector(buttonWasTapped), for: .touchUpInside)
button.setContentHuggingPriority(.required, for: .vertical)
button.setContentCompressionResistancePriority(.required, for: .vertical)
stackView.addArrangedSubview(button)

detailLabel.translatesAutoresizingMaskIntoConstraints = false
detailLabel.text = "Hello, world!"
detailLabel.textAlignment = .center
detailLabel.backgroundColor = UIColor.purple.withAlphaComponent(0.2)
detailLabel.heightAnchor.constraint(equalToConstant: 80).isActive = true

detailContainer.translatesAutoresizingMaskIntoConstraints = false
detailContainer.clipsToBounds = true
detailContainer.addSubview(detailLabel)
let bottomConstraint = detailLabel.bottomAnchor.constraint(equalTo: detailContainer.bottomAnchor)
bottomConstraint.priority = .init(999)
NSLayoutConstraint.activate([
detailLabel.topAnchor.constraint(equalTo: detailContainer.topAnchor),
detailLabel.leadingAnchor.constraint(equalTo: detailContainer.leadingAnchor),
detailLabel.trailingAnchor.constraint(equalTo: detailContainer.trailingAnchor),
bottomConstraint
])
stackView.addArrangedSubview(detailContainer)

self.view = stackView
}

private let stackView = UIStackView()
private let button = UIButton(type: .roundedRect)
private let detailLabel = UILabel()
private let detailContainer = UIView()
private var detailContainerHideConstraint: NSLayoutConstraint?
}

关于swift - UIStackView 动画问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52798139/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com