swift 当自动布局试图减小堆栈视图大小时,是否隐藏堆栈视图中的视图?

laik7k3q  于 2023-06-04  发布在  Swift
关注(0)|答案(1)|浏览(240)

我有一个UIStackView,它包含多个排列的子视图。当自动布局试图减小堆栈视图的大小时,我想动态地隐藏堆栈视图中的某些视图。我正在寻找一种方法来实现这一行为使用自动布局,而无需手动操纵帧。
我已经尝试设置子视图的isHidden属性,但似乎不能正确更新堆栈视图的布局。这些视图仍然占用堆栈视图中的空间。
当自动布局试图减小堆栈视图的大小时,建议使用什么方法来隐藏堆栈视图中的视图?是否有任何特定的方法或技术应该用来实现这种行为?
任何指导或代码示例将不胜感激。谢谢你!
我尝试覆盖layoutSubviews方法。

override func layoutSubviews() {
        super.layoutSubviews()

        for view in stackView.arrangedSubviews {
            if visibilityManager.shouldBeVisible(view: view) {
                if let view = view as? MyButton {
                    if view.intrinsicContentSize.height > view.bounds.height {
                        view.isHidden = true
                    } else {
                        view.isHidden = false
                    }
                }
            }
        }
    }

期望:堆栈视图中的视图将被隐藏
实际:视图只是被压缩

ca1c2owp

ca1c2owp1#

当我们在堆栈视图的排列子视图上设置.isHidden = true时,该子视图仍然在.arrangedSubviews集合中,但它从层次结构中被删除,不再具有有效的框架。
另一种方法是将.alpha设置为1.00.0以“显示/隐藏”视图。
我们创建了一个自定义视图子类--我们称之为AutoHideSubviewsView。它将有一个带有Top / Leading / Trailing约束的堆栈视图,但***没有Bottom约束***。
当视图框改变时-变得更短或更高-我们循环通过排列的子视图并且:

  • 得到框架
  • 将其转换到视图坐标空间(它相对于堆栈视图本身)
  • 如果视图的边界包含框架,则设置其.alpha = 1.0(显示它)
  • 否则,设置其.alpha = 0.0(隐藏它)

下面是一些快速的示例代码。。

自定义视图

class AutoHideSubviewsView: UIView {
    
    let stackView: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.spacing = 12.0
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        addSubview(stackView)
        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
            stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
            stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
            // NO Bottom constraint
        ])
        // not strictly necessary, but let's do this anyway
        self.clipsToBounds = true
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // on first layout, the stackView's subview's frames are not set
        //  so force another layout pass
        if stackView.arrangedSubviews.first!.frame.height == 0.0 {
            stackView.setNeedsLayout()
            stackView.layoutIfNeeded()
            self.setNeedsLayout()
            self.layoutIfNeeded()
            return
        }
        for v in stackView.arrangedSubviews {
            // the frames of the arranged subviews are
            //  relative to the stack view frame, so
            //  we want to convert the frames in case
            //  the stack view TOP is not Zero
            let r = stackView.convert(v.frame, to: self)
            // animate the alpha change so we can see it
            UIView.animate(withDuration: 0.3, animations: {
                v.alpha = self.bounds.contains(r) ? 1.0 : 0.0
            })
        }
    }
    
}

示例控制器

class ViewController: UIViewController {
    
    let ahView = AutoHideSubviewsView()
    
    var hConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        
        // grow and shrink buttons
        var cfg = UIButton.Configuration.gray()
        cfg.title = "Shrink"
        let btn1 = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
            if self.hConstraint.constant > 15.0 {
                self.hConstraint.constant -= 10.0
            }
        })
        cfg.title = "Grow"
        let btn2 = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
            self.hConstraint.constant += 10.0
        })

        [ahView, btn1, btn2].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(v)
        }

        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            
            ahView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            ahView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            ahView.widthAnchor.constraint(equalToConstant: 200.0),
            
            btn1.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            btn1.leadingAnchor.constraint(equalTo: ahView.trailingAnchor, constant: 20.0),
            btn1.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            
            btn2.topAnchor.constraint(equalTo: btn1.bottomAnchor, constant: 20.0),
            btn2.leadingAnchor.constraint(equalTo: ahView.trailingAnchor, constant: 20.0),
            btn2.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            
        ])
        
        // start with the view height at 320
        hConstraint = ahView.heightAnchor.constraint(equalToConstant: 320.0)
        hConstraint.isActive = true
        
        // let's add 3 labels and 3 buttons to the custom view's stackView
        let strings: [String] = ["First", "Second", "Third"]
        let colors: [UIColor] = [.cyan, .green, .yellow]
        for (str, c) in zip(strings, colors) {
            let label = UILabel()
            label.font = .systemFont(ofSize: 24, weight: .light)
            label.text = str
            label.textAlignment = .center
            label.backgroundColor = c
            label.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
            var cfg = UIButton.Configuration.filled()
            cfg.title = str
            let btn = UIButton(configuration: cfg, primaryAction: UIAction() { _ in
                print("\(str) Button Tapped")
            })
            ahView.stackView.addArrangedSubview(label)
            ahView.stackView.addArrangedSubview(btn)
        }

        // so we can see the framing
        ahView.backgroundColor = .red
    }
    
}

如下所示(自定义视图的背景为红色):

点击“收缩”按钮将降低视图的高度,点击“增长”按钮将增加它。

为了使它更容易看到发生了什么,我对.alpha的变化进行了动画处理,这样子视图就可以“淡入淡出”。
下面是一个动画(太大了,无法在这里发布):https://imgur.com/a/glRRh2O

相关问题