使用 hidesBarsOnSwipe 更新 ProgressView 的约束

Posted

技术标签:

【中文标题】使用 hidesBarsOnSwipe 更新 ProgressView 的约束【英文标题】:Updating Constraints for ProgressView with hidesBarsOnSwipe 【发布时间】:2015-11-09 10:05:13 【问题描述】:

我正在尝试在 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://***.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 横向显示时不可见(覆盖)

有什么建议吗?

【问题讨论】:

【参考方案1】:

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

【讨论】:

以上是关于使用 hidesBarsOnSwipe 更新 ProgressView 的约束的主要内容,如果未能解决你的问题,请参考以下文章

使用 self.navigationController.hidesBarsOnSwipe = true 隐藏导航栏,将其永久隐藏

hidesBarsOnSwipe 不起作用

iOS hidesBarsOnSwipe 状态栏背景颜色

UINavigationController.hidesBarsOnSwipe=YES 导致 NSInternalInconsistencyException

Swift iOS -NavigationBar hidesBarsOnSwipe 在状态栏下设置 CollectionView Frame 时永远不会重新出现

GitHub Actions:某些文件更新的自动 PR?