首页 > 解决方案 > 当 isHidden == true 时 UIStackView 从左侧动画

问题描述

我有一个 UIStackView 和一堆排列的子视图。我希望它们都隐藏在 viewDidLoad 所以我去做

public func setStackViewHidden(_ isHidden: Bool, animated: Bool) {
    stackView.arrangedSubviews.forEach ({ subview in
        if animated {
            UIView.animate(withDuration: 0.3) {
                subview.isHidden = isHidden
            }
        } else {
            subview.isHidden = isHidden
        }
    })
}

这使得整个 stackView 隐藏起来。然后当我去使用与 isHidden == false 相同的方法时。它从左侧开始动画并向右扩展至正确的大小。为什么它不是从正确的宽度到底部的动画,而是从左边到整个尺寸?

标签: xcodejquery-animateuistackview

解决方案


显示/隐藏排列的子视图时使用的内置动画UIStackView可以很好地工作 --- 它可能不太好。

堆栈视图所做的关键事情之一是安排其子视图。当然,也经常使用子视图的宽度和高度来确定堆栈视图的宽度和高度。所以我们可以得到未定义的状态,并且动画——正如你所看到的——变得“不稳定”。

试一试(所有代码,没有@IBOutletsor @IBActions,所以只需为这个类分配一个视图控制器):

class StackShowHideViewController: UIViewController {

    // UIButton
    let btn: UIButton = {
        let v = UIButton()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.setTitle("Tap Me", for: .normal)
        v.backgroundColor = .red
        return v
    }()

    // vertical UIStackView
    let stackView: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .vertical
        v.alignment = .fill
        v.distribution = .fill
        v.spacing = 8
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // add elements to view
        view.addSubview(btn)
        view.addSubview(stackView)

        NSLayoutConstraint.activate([

            // constrain button 20-pts from top, centered horizontally
            btn.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20.0),
            btn.centerXAnchor.constraint(equalTo: view.centerXAnchor),

            // constrain stack view 20-pts from bottom of button
            // centered horizontally
            // width constrained to 160-pts
            stackView.topAnchor.constraint(equalTo: btn.bottomAnchor, constant: 20.0),
            stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            stackView.widthAnchor.constraint(equalToConstant: 160.0),

        ])

        // add 5 UILabels to the stack view
        for i in 1...5 {
            let v = UILabel()
            v.backgroundColor = .yellow
            v.text = "This is Label \(i)"
            v.textAlignment = .center
            v.translatesAutoresizingMaskIntoConstraints = false
            // inititially hidden
            v.isHidden = true
            // add label to stack view
            stackView.addArrangedSubview(v)
            // constrain label widths to width of stack view
            v.widthAnchor.constraint(equalTo: stackView.widthAnchor).isActive = true
        }

        btn.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)

    }

    public func setStackViewHidden(_ isHidden: Bool, animated: Bool) {
        stackView.arrangedSubviews.forEach ({ subview in
            if animated {
                UIView.animate(withDuration: 0.3) {
                    subview.isHidden = isHidden
                }
            } else {
                subview.isHidden = isHidden
            }
        })
    }

    @objc func didTap(_ sender: Any) {
        // if labels are hidden, show them
        // else, hide them
        var h = true
        if let v = stackView.arrangedSubviews.first {
            h = v.isHidden
        }
        setStackViewHidden(!h, animated: true)
    }

}

推荐阅读