使用hidesBarsOnSwipe更新ProgressView的约束

时间:2015-11-09 10:05:13

标签: ios xcode swift autolayout

我正在尝试在UINavigationBar中显示进度条,如下所述:Showing a UIProgressView inside or on top of a UINavigationController's UINavigationBar

在Swift中完成后,自定义UINavigationController类看起来像这样:

class NavigationControllerWithProgress: UINavigationController {

    var progressView: UIProgressView!
    var progressBottomConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()

        hidesBarsOnSwipe = true
        hidesBarsWhenVerticallyCompact = true

        // adding ProgressView to UINavigationController to allow it to be placed inside the UINavigationBar
        // see: https://stackoverflow.com/questions/19211999/showing-a-uiprogressview-inside-or-on-top-of-a-uinavigationcontrollers-uinaviga
        progressView = UIProgressView(progressViewStyle: UIProgressViewStyle.Bar)
        view.addSubview(progressView)

        progressView.translatesAutoresizingMaskIntoConstraints = false
        progressView.setProgress(0.5, animated: false)

        progressBottomConstraint = NSLayoutConstraint(item: progressView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self.navigationBar, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: -0.5)
        view.addConstraint(progressBottomConstraint)

        var constraint: NSLayoutConstraint

        constraint = NSLayoutConstraint(item: progressView, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0)
        view.addConstraint(constraint)

        constraint = NSLayoutConstraint(item: progressView, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0)
        view.addConstraint(constraint)
    }
}

问题:只要OnSwipe / WhenVerticallyCompact自动隐藏UINavigationBar,约束就会停止工作,即ProgressView在StatusBar下放错位置。

我尝试在updateViewConstraints()和/或viewWillLayoutSubviews()中更新它,这是我目前看到的唯一方式。

由于常量已用于相对于UINavigationBar分隔符的位置(请参阅链接的SO线程),我尝试这个来测试此情况下的updateViewContraints():

override func updateViewConstraints() {
    super.updateViewConstraints()

    view.removeConstraint(progressBottomConstraint)
    progressBottomConstraint = NSLayoutConstraint(item: progressView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.navigationBar, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 30)
    view.addConstraint(progressBottomConstraint)
}

请注意此测试的常量设置为30.

通过这样做,我可以看到约束对自动隐藏UINavigationBar不起作用:隐藏/显示带旋转的导航栏(垂直紧凑时)或滑动栏是

  • 在UINavigationBar下以30像素画像,但是
  • 在UINavigationBar隐藏在风景中的最顶端
  • 当UINavigationBar以横向显示时隐藏(覆盖)

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

虽然可以通过代码进行自动布局约束来实现这一点,但是使用组件(这里是SnapKit)使它变得更加简单:

override func viewDidLoad() {
    super.viewDidLoad()

    [...]
    progressView.snp_makeConstraints { (make) -> Void in
        progressViewTopConstraint = make.top.equalTo(snp_topLayoutGuideBottom).offset(-2.5).constraint
        make.left.equalTo(view).offset(0)
        make.right.equalTo(view).offset(0)
    }
}

func updateProgressViewConstraint() {
    let navBarHeight = navigationBar.frame.size.height
    progressViewTopConstraint?.updateOffset(navigationBar.hidden ? 0 : navBarHeight - 2.5)
    view.bringSubviewToFront(progressView)
}

override func viewWillLayoutSubviews() {
    updateProgressViewConstraint()
    super.viewWillLayoutSubviews()
}

updateViewConstraints()是更好的覆盖方法,但在这种情况下新的hidesBarOnSwipe存在问题(错误定位progressView)。

注意:在UINavigationController中执行此操作时,progressView仍会跳转(即UINavigationBar完成转换后的位置设置),所以我现在将其移动到View本身。

编辑:将它放在视图本身可以修复条形图的跳跃,但当然不允许将UIProgressView放在UINavigationBar中。