ios - 使用 hidesBarsOnSwipe 更新 ProgressView 的约束

标签 ios xcode swift autolayout

我正在尝试在 UINavigationBar 中显示一个进度条,就像这里讨论的那样:Showing a UIProgressView inside or on top of a UINavigationController's UINavigationBar .

自定义 UINavigationController 类在 Swift 中完成时如下所示:

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

问题:一旦 UINavigationBar 被 OnSwipe/WhenVerticallyCompact 自动隐藏,约束就会停止工作,即 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 横向显示时不可见(被覆盖)

有什么建议吗?

最佳答案

虽然可以通过代码使用自动布局约束来完成此操作,但使用组件(此处为 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 本身。

编辑:将其放置在 View 中本身修复了栏的跳跃,但当然不允许将 UIProgressView 放置在 UINavigationBar 中。

关于ios - 使用 hidesBarsOnSwipe 更新 ProgressView 的约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33606645/

相关文章:

ios - 单元测试 : Is there ways to see code coverage for Swift?

ios - Ionic Cordova iOS xxx 不支持预配配置文件 Azure Pipelines

ios - Swift 编译器错误 : "Expression too complex" on a string concatenation

ios - 使用 CoreData 和捆绑的 SQLite 数据库?

ios 6.0 新地址簿 ABAddressBookRequestAccessWithCompletion

ios - AppList 数据源在 -[NSIndexPath row] 中断言失败

ios - iOS 的动态机器学习模型

ios - 信号 sigabrt 委托(delegate) -> AppDelegate.swift

ios - Cordova 试图调用电话号码

ios - UIImagePickerController 以大写字母 "USE_PHOTO"、 "RETAKE"和图库图像 "CAMERA_ROLL"显示文本?