UIStackView在iOS 9上更改hidden属性时无法实现动画效果

13

我正在使用 Stack View 创建一种表格 UI,StackView 中有 6 个视图,其中 0、2、4 可见,1、3、5 隐藏。当点击其中一个可见视图时,我希望“打开”一个隐藏的视图。

我有这段代码,在 iOS 10 上运行良好,但由于某些原因我无法理解,在 iOS 9 上无法正常工作。

请注意,如果我加载所有视图,则关闭动画将起作用,但在将 hidden 属性设置为 false 时不会打开。

以下是我的代码 -

编辑 经过一些调试,看起来视图高度约束没有从隐藏中恢复,并且它的框架仍然是高度为 0。

 import UIKit

class DeckView: UIView {

}

class ViewController: UIViewController {

var scrollView: UIScrollView!
var stackView: UIStackView!

override func viewDidLoad() {
    super.viewDidLoad()

    scrollView = UIScrollView()
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(scrollView)

    view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[scrollView]|", options: .alignAllCenterX, metrics: nil, views: ["scrollView": scrollView]))
    view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[scrollView]|", options: .alignAllCenterX, metrics: nil, views: ["scrollView": scrollView]))


    stackView = UIStackView()
    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.spacing = 0
    stackView.alignment = .center
    stackView.distribution = .fillProportionally
    stackView.axis = .vertical
    scrollView.addSubview(stackView)

    scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[stackView]|", options: NSLayoutFormatOptions.alignAllCenterX, metrics: nil, views: ["stackView": stackView]))
    scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[stackView]|", options: NSLayoutFormatOptions.alignAllCenterX, metrics: nil, views: ["stackView": stackView]))


    for i in 0 ..< 8 {
        let view  = DeckView()
        view.tag = i
        view.translatesAutoresizingMaskIntoConstraints = false
        view.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true
        view.isUserInteractionEnabled = true

        if i%2 == 0 {
            view.backgroundColor   = UIColor.magenta
            let constriant = view.heightAnchor.constraint(equalToConstant:160)
            constriant.priority = 999
            view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.openDeck(_:))))
            view.addConstraint(constriant)

        } else {
            view.backgroundColor   = UIColor.red
            let constriant = view.heightAnchor.constraint(equalToConstant:160)
            constriant.priority = 999
            view.addConstraint(constriant)
            view.isHidden = false
        }

        stackView.addArrangedSubview(view)
    }
}

func openDeck(_ sender:UIGestureRecognizer) {
    if let view = sender.view as? DeckView,
    let childView = stackView.viewWithTag(view.tag + 1) {
            UIView.animate(withDuration: 0.4, animations: {
                childView.isHidden = !childView.isHidden
            })
    }
}
}
2个回答

49
  1. 将视图的高度优先级保持低于1000(设为999)。
  2. 如果已经隐藏,请勿设置setHidden:true(这是UIStackView的错误)。

我的意思是,如果您能发布雷达或错误ID。 - blackjacx
6
非常感谢您做出这样的贡献。2015年的两个问题(radars UIStackView:切换隐藏状态时动画卡住在UIStackView上调用setHidden:NO不总是显示它,由@blackjacx请求)以及第二步的解决方案,都在2017年8月仍然有效。需要提到的是,我不需要执行第一步(distribution =.fill 对我来说可以正常工作)。这个bug显然与动画有关,因为当我立即切换 isHidden 时,它没有出现。 - Jamie Birch
2
这篇文章和这篇文章解释了vats的第一步背后的原因。简而言之:“基本上,这里发生的是,垂直堆栈视图将自动将视图的高度设置为0像素以隐藏它。但是,如果它具有冲突的约束条件,例如填充,可能会尝试保持其高度为16像素,那么您需要降低这些约束条件的优先级,以允许在隐藏时将其缩短到0像素高度。” - Jamie Birch
1
@vats 这个isHidden动画的bug困扰我已经好几周了。非常感谢! - HuaTham
3
iOS 13 中这仍然存在 -_____________________-' - J. Doe
显示剩余4条评论

2

如果有人遇到这个问题。

我通过删除 - 来解决了这个问题。

stackView.distribution = .fillProportionally

我不确定为什么会出现这种情况,但我发现自动布局添加了一个名为“UISV-fill-proportionally”的高度约束,其常数为0,并且优先级大于我的高度约束。移除fillProportionally解决了问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接