代码之家  ›  专栏  ›  技术社区  ›  Stefan

设置为活动时自动布局约束中断

  •  3
  • Stefan  · 技术社区  · 6 年前

    我有一组AL约束来定位子vc,它有两个位置,展开和折叠。

    我发现,当我添加折叠约束时,一个带有常量的顶部锚定到底部锚定约束,当vc第一次创建时,当我激活它时,似乎有额外的间距。似乎是因为当时没有实际的高度。

    当我在viewDidLayoutSubviews中添加约束时,额外的间距消失了,约束行为正常。除了现在当我在动画中的约束之间切换时,当我切换到展开的约束和约束断开时,我不能停用折叠的约束。可能是因为viewDidLayoutSubviews在整个转换动画中被调用。

    下面是vc设置的摘要。

    var foregroundExpandedConstraint: NSLayoutConstraint!
    var foregroundCollapsedConstraint: NSLayoutConstraint!
    
    var foregroundViewController: UIViewController? {
        didSet {
    
            setupforegroundViewController(foregroundViewController: foregroundViewController!)
        }
    }
    
    func setupforegroundViewController(foregroundViewController: UIViewController) {
    
        addChildViewController(foregroundViewController)
        foregroundViewController.didMove(toParentViewController: self)
    
        guard let foregroundView = foregroundViewController.view else { return }
        foregroundView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(foregroundView)
    
        foregroundExpandedConstraint = foregroundView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 15)
    
        let height =  view.safeAreaLayoutGuide.layoutFrame.height - 50 - 15
        let cellHeight = ((height) / 6)        
        foregroundCollapsedConstraint = NSLayoutConstraint(item: foregroundView, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: (-cellHeight) * 2 - 50)
    
        let foregroundViewControllerViewConstraints = [
            foregroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            foregroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            foregroundView.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor, constant: -50 - 15),
            foregroundExpandedConstraint!
            ]
    
    
        NSLayoutConstraint.activate(foregroundViewControllerViewConstraints)
    }
    

    在这里,动画是使用UIViewPropertyAnimator来实现的。

    func animateTransitionIfNeeded(state: ForegroundState, duration: TimeInterval) {
    
        let containerFrameAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1) {
            [unowned self] in
    
            switch state {
            case .expanded:
                self.foregroundCollapsedConstraint?.isActive = false
                self.foregroundExpandedConstraint?.isActive = true
                self.view.layoutIfNeeded()
            case .collapsed:
                self.foregroundExpandedConstraint?.isActive = false
                self.foregroundCollapsedConstraint?.isActive = true
                self.view.layoutIfNeeded()
            }
        }
    
        containerFrameAnimator.addCompletion {  [weak self] (position) in
    
            if position == .start {
                switch state {
                case .collapsed:
                    self?.foregroundCollapsedConstraint?.isActive = false
                    self?.foregroundExpandedConstraint?.isActive = true
                    self?.foregroundIsExpanded = true
                    self?.view.layoutIfNeeded()
                case .expanded:
                    self?.foregroundExpandedConstraint?.isActive = false
                    self?.foregroundCollapsedConstraint?.isActive = true
                    self?.foregroundIsExpanded = false
                    self?.view.layoutIfNeeded()
                }
            } else if position == .end {
                switch state {
                case .collapsed:
                    self?.foregroundExpandedConstraint?.isActive = false
                    self?.foregroundCollapsedConstraint?.isActive = true
                    self?.foregroundIsExpanded = false
                case .expanded:
                    self?.foregroundExpandedConstraint?.isActive = false
                    self?.foregroundCollapsedConstraint?.isActive = true
                    self?.foregroundIsExpanded = true
                }
            }
            self?.runningAnimations.removeAll()
        }
    

    再次重申,当我使用以下代码时,将约束设置为vc添加到视图层次结构中时,它的布局不正确。检查约束,我看到它们在调用view-did布局子视图后发生了变化。除了折叠的约束外,每个约束都会相应地更改。

    当我在view-did布局子视图中添加收拢的约束时,它的行为正常,但是我无法停用它,并且约束中断。

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        let height =  view.safeAreaLayoutGuide.layoutFrame.height - 50 - 15
        let cellHeight = ((height) / 6)
    
        if let v = foregroundViewController?.view {
            foregroundCollapsedConstraint = NSLayoutConstraint(item: v, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: (-cellHeight) * 2 - 50)
        }
    }
    

    我已经创建了一个回购协议来证明这个问题: https://github.com/louiss98/UIViewPropertyAnimator-Layout-Test

    1 回复  |  直到 6 年前
        1
  •  0
  •   DonMag    6 年前

    您可以通过更改常量而不是创建新的约束来消除“断开”约束。

    在你的 viewDidLayoutSubviews() 功能,

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        let height =  view.safeAreaLayoutGuide.layoutFrame.height - 50 - 15
        let cellHeight = ((height) / 6)
    
        foregroundCollapsedConstraint = NSLayoutConstraint(item: testViewController.view, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: (-cellHeight) * 2 - 50)
    }
    

    收件人:

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        let height =  view.safeAreaLayoutGuide.layoutFrame.height - 50 - 15
        let cellHeight = ((height) / 6)
    
        foregroundCollapsedConstraint.constant = (-cellHeight) * 2 - 50
    }