首页 > 解决方案 > Swift - UIStackView - 如果所有项目的高度低于阈值,则隐藏

问题描述

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

我试图扩展UIButton和添加:

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

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

标签: uibuttonuistackviewlayoutsubviews

解决方案


不清楚你在做什么,或者为什么你说设置按钮的.alpha属性会有问题,但这里有两种方法,既使用UIStackView子类又处理显示/隐藏在layoutSubviews().

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根据按钮高度设置属性(更简单):

    类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
         }
    
     }
    

    }

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

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
    }

}

推荐阅读