Swift - UIStackView - 如果所有项目的高度都低于阈值则隐藏

Swift - UIStackView - hide if height of all items is below threshold

我有 UIStackView 的垂直模式填充 UIButtons。我有动态屏幕调整大小,如果堆栈视图中的所有按钮的高度都低于某个阈值,我想隐藏它们。如何自动实现?

我尝试扩展 UIButton 并添加:

override func layoutSubviews() {
    super.layoutSubviews()
    self.isHidden = (self.frame.height < 20)
}

有效,但是一旦按钮被隐藏,它就永远不会重新出现并且 layoutSubviews 永远不会被回调(即使高度应该再次变大)。

不清楚你在做什么,也不清楚你为什么说设置按钮 .alpha 属性 会有问题,但这里有两种方法,都使用 UIStackView subclass 并处理 layoutSubviews().

中的 show/hide

1: 计算按钮高度 将是 并设置 .isHidden 属性:

class MyStackView: UIStackView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        axis = .vertical
        distribution = .fillEqually
        spacing = 8
    }
    override func layoutSubviews() {
        super.layoutSubviews()

        // approach 1
        //  setting .isHidden
        let numViews = arrangedSubviews.count
        let numSpaces = numViews - 1
        let h = (bounds.height - (spacing * CGFloat(numSpaces))) / CGFloat(numViews)
        let bHide = h < 20
        arrangedSubviews.forEach { v in
            v.isHidden = bHide
        }
        
    }
    
}
  1. 根据按钮高度 设置 .isHidden 属性(更简单):

    class MyStackView: UIStackView {

     override init(frame: CGRect) {
         super.init(frame: frame)
         commonInit()
     }
     required init(coder: NSCoder) {
         super.init(coder: coder)
         commonInit()
     }
     func commonInit() -> Void {
         axis = .vertical
         distribution = .fillEqually
         spacing = 8
     }
     override func layoutSubviews() {
         super.layoutSubviews()
    
         // approach 2
         //  setting .alpha
         arrangedSubviews.forEach { v in
             v.alpha = v.frame.height < 20 ? 0.0 : 1.0
         }
    
     }
    

    }

这是一个示例控制器,可以看到它的使用情况。点击任意位置将在 300100 之间切换堆栈视图的高度(按钮在 100 处的高度将小于 20 磅):

class ConditionalStackViewController: UIViewController {
    
    let stackView: MyStackView = {
        let v = MyStackView()
        // so we can see the stack view frame
        v.backgroundColor = .systemYellow
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var stackHeight: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        for i in 1...6 {
            let b = UIButton()
            b.setTitle("Button \(i)", for: [])
            b.setTitleColor(.white, for: .normal)
            b.setTitleColor(.lightGray, for: .highlighted)
            b.backgroundColor = .red
            stackView.addArrangedSubview(b)
        }
        
        view.addSubview(stackView)
        
        let g = view.safeAreaLayoutGuide
        
        stackHeight = stackView.heightAnchor.constraint(equalToConstant: 300.0)
        
        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            stackHeight,
        ])
        
        let t = UITapGestureRecognizer(target: self, action: #selector(gotTap(_:)))
        view.addGestureRecognizer(t)
    }
    
    @objc func gotTap(_ g: UITapGestureRecognizer) -> Void {
        stackHeight.constant = stackHeight.constant == 300 ? 100 : 300
    }

}