SuperViews约束发生变化时更新SubView约束

时间:2018-07-05 11:53:05

标签: ios swift uiview autolayout nslayoutconstraint

我在UIView上方有一个UITableView(如屏幕截图所示)。当用户滚动UIView时,我将UITableView从屏幕上移出(从顶部)。 UIView可以正确移动,但是UIView中的项目保持在原位置。我怎么也可以移动它们?

P.S:我从下面的帖子中得到了帮助,并感谢它的发布者:),也为许多代码感到抱歉,但是我无法决定如何缩小它。

https://github.com/MichiganLabs/AnimatingTableViewHeader

编辑:我通过将所有约束添加到同一视图来做错了,我已解决了该问题,但问题仍然存在。

    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    self.view.backgroundColor = UIColor.white
    setupUI()

}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.headerHeightConstraint.constant = self.maxHeaderHeight
    updateHeader()
}

private func setupUI(){
    self.view.backgroundColor = UIColor.white
    self.tableView.delegate = self
    self.tableView.dataSource = self
    self.headerView.backgroundColor = Color.Common.welcomeScreenBackgroundColor.withAlphaComponent(0.5)
    self.view.addSubview(tableView)
    self.view.addSubview(headerView)
    headerView.translatesAutoresizingMaskIntoConstraints = false
    tableView.translatesAutoresizingMaskIntoConstraints = false
    //cityBtn.translatesAutoresizingMaskIntoConstraints = false
    cityLbl.text = "İL"
    headerView.addSubview(cityLbl)
    headerView.addSubview(cityBtn)


    //Header = 20 from left edge of screen
    let cn1 = NSLayoutConstraint(item: headerView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1.0, constant: 20)
    //Header view trailing end is 20 px from right edge of the screen
    let cn2 = NSLayoutConstraint(item: headerView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1.0, constant: -20)
    let cn3 = NSLayoutConstraint(item: headerView, attribute: .bottom, relatedBy: .equal, toItem: self.tableView, attribute: .top, multiplier: 1.0, constant: -20)
    //Header view height = constant 240
    headerHeightConstraint = NSLayoutConstraint(item: headerView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant:230)
    //Header view vertical padding from the top edge of the screen = 20
    let topConstraint = NSLayoutConstraint(item: headerView, attribute: .top, relatedBy: .equal, toItem: self.topLayoutGuide, attribute: .bottom, multiplier: 1.0, constant: 20)

    //Header = 20 from left edge of screen
    let tb1 = NSLayoutConstraint(item: tableView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1.0, constant: 0)
    //Header view trailing end is 20 px from right edge of the screen
    let tb2 = NSLayoutConstraint(item: tableView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1.0, constant: 0)
    let tb3 = NSLayoutConstraint(item: tableView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: 0)
    let tb4 = NSLayoutConstraint(item: tableView, attribute: .top, relatedBy: .equal, toItem: self.headerView, attribute: .bottom, multiplier: 1.0, constant: 0)


    //Header view trailing end is 20 px from right edge of the screen
    let cb1 = NSLayoutConstraint(item: cityBtn, attribute: .width, relatedBy: .equal, toItem: self.headerView, attribute: .width, multiplier: 0.6, constant: 0)
    let cb2 = NSLayoutConstraint(item: cityBtn, attribute: .trailing, relatedBy: .equal, toItem: self.headerView, attribute: .trailing, multiplier: 1.0, constant: -20)
    cityBtnTopConstraint = NSLayoutConstraint(item: cityBtn, attribute: .top, relatedBy: .equal, toItem: self.headerView, attribute: .top, multiplier: 1.0, constant: 20)
    let cb4 = NSLayoutConstraint(item: cityBtn, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant:50)

          self.view.addConstraints([cn1,cn2,cn3,headerHeightConstraint,topConstraint,tb1,tb2,tb3,tb4])
self.headerView.addConstraints([cb1,cb2,cityBtnTopConstraint,cb4])

}
override func viewDidLayoutSubviews() {
    cityLbl.leftAnchor.constraint(equalTo: headerView.leftAnchor, constant: 20).isActive = true
    cityLbl.centerYAnchor.constraint(equalTo: cityBtn.centerYAnchor).isActive = true
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let scrollDiff = scrollView.contentOffset.y - self.previousScrollOffset

    let absoluteTop: CGFloat = 0;
    let absoluteBottom: CGFloat = scrollView.contentSize.height - scrollView.frame.size.height;

    let isScrollingDown = scrollDiff > 0 && scrollView.contentOffset.y > absoluteTop
    let isScrollingUp = scrollDiff < 0 && scrollView.contentOffset.y < absoluteBottom

    if canAnimateHeader(scrollView) {

        // Calculate new header height
        var newHeight = self.headerHeightConstraint.constant
        if isScrollingDown {
            newHeight = max(self.minHeaderHeight, self.headerHeightConstraint.constant - abs(scrollDiff))
        } else if isScrollingUp {
            newHeight = min(self.maxHeaderHeight, self.headerHeightConstraint.constant + abs(scrollDiff))
        }

        // Header needs to animate
        if newHeight != self.headerHeightConstraint.constant {
            self.headerHeightConstraint.constant = newHeight
            self.updateHeader()
            self.setScrollPosition(self.previousScrollOffset)
        }

        self.previousScrollOffset = scrollView.contentOffset.y
    }
}

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    self.scrollViewDidStopScrolling()
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !decelerate {
        self.scrollViewDidStopScrolling()
    }
}

func scrollViewDidStopScrolling() {
    let range = self.maxHeaderHeight - self.minHeaderHeight
    let midPoint = self.minHeaderHeight + (range / 2)

    if self.headerHeightConstraint.constant > midPoint {
        self.expandHeader()
    } else {
        self.collapseHeader()
    }
}

func canAnimateHeader(_ scrollView: UIScrollView) -> Bool {
    // Calculate the size of the scrollView when header is collapsed
    let scrollViewMaxHeight = scrollView.frame.height + self.headerHeightConstraint.constant - minHeaderHeight

    // Make sure that when header is collapsed, there is still room to scroll
    return scrollView.contentSize.height > scrollViewMaxHeight
}

func collapseHeader() {
    self.view.layoutIfNeeded()
    UIView.animate(withDuration: 0.2, animations: {
        self.headerHeightConstraint.constant = self.minHeaderHeight
        self.updateHeader()
        self.view.layoutIfNeeded()
    })
}

func expandHeader() {
    self.view.layoutIfNeeded()
    UIView.animate(withDuration: 0.2, animations: {
        self.headerHeightConstraint.constant = self.maxHeaderHeight
        self.updateHeader()
        self.view.layoutIfNeeded()
    })
}

func setScrollPosition(_ position: CGFloat) {
    self.tableView.contentOffset = CGPoint(x: self.tableView.contentOffset.x, y: position)
}

func updateHeader() {
    let range = self.maxHeaderHeight - self.minHeaderHeight
    let openAmount = self.headerHeightConstraint.constant - self.minHeaderHeight
    let percentage = openAmount / range

    self.cityBtn.alpha = percentage
    //self.titleTopConstraint.constant = -openAmount + 10
    //self.logoImageView.alpha = percentage
}

1 个答案:

答案 0 :(得分:0)

问题是您将所有约束添加到self.view中,需要在headerView和headerView的子视图之间添加约束,因此请拆分

self.view.addConstraints([cn1,cn2,cn3,headerHeightConstraint,topConstraint,tb1,tb2,  tb3,tb4,cb1,cb2,cityBtnTopConstraint,cb4])

self.view.addConstraints([cn1,cn2,cn3,headerHeightConstraint,topConstraint,tb1,tb2,  tb3,tb4])

&&

headerView.addConstraints([cb1,cb2,cityBtnTopConstraint,cb4])