【问题标题】:How to properly refresh a UINavigationBar?如何正确刷新 UINavigationBar?
【发布时间】:2016-08-21 15:59:43
【问题描述】:

关于这个问题:How to change Back button text from within the child view controller? 我正在寻找一种在使用previousViewController.navigationItem.backBarButtonItem?.title = "New Title" 更改后退按钮标题后刷新导航栏的正确方法。

链接问题的(不太理想?)解决方案:

if let navigationController = self.navigationController {
    navigationController.popViewControllerAnimated(false)
    navigationController.pushViewController(self, animated: false)
}

编辑:

显然更改图层框架会强制导航栏刷新。我猜这不是解决方案,而是更便宜(?)的解决方法:

if let navigationController = self.navigationController {
    navigationController.navigationBar.layer.frame.insetInPlace(dx: 0.1, dy: 0)
    navigationController.navigationBar.layer.frame.insetInPlace(dx: -0.1, dy: 0)
}

【问题讨论】:

  • 很多时候,当没有直接的方法来做你想做的事情时,这是有充分理由的。后退按钮应该将用户带回到他们来自的地方,并且他们的导航历史不应该被重写。如果您在左上角需要某种其他类型的行为(除了导航返回),则无需使用backBarButtonItem
  • 在某些特定情况下更改标题可以改善用户体验。以 WhatsApp 为例。
  • 假设我从未使用过 WhatsApp。
  • @MJQZ1347 所以我检查了我的 iPhone 上的 WhatsApp,以防我错过了什么——我很肯定他们每次切换到另一个 VC 时只是在创建 UIBarButtonItem;我看不到“刷新”,即在同一个 VC 中更改按钮的标题

标签: ios swift cocoa-touch


【解决方案1】:

在尝试了各种刷新方法后,我发现这是看起来最不难看的解决方案(当时在 iOS 10 但目前显然不在 iOS 13 上,即不要指望这):

guard let navigation = navigationController,
      !(navigation.topViewController === self) else {
    return
}
let bar = navigation.navigationBar
bar.setNeedsLayout()
bar.layoutIfNeeded()
bar.setNeedsDisplay()

尝试了其他方法:

  • 呈现视图控制器(在某些情况下会导致屏幕闪烁)
  • 隐藏和重新显示栏(如果在向后滑动到上一个 VC 之间的中途断开栏)
  • 设置栏的图层框架(似乎不能可靠地工作,navigationBar 的文档明确禁止)

【讨论】:

  • @airowe 这也是一个通过反复试验发现的奇怪黑客。不幸的是,我不知道更好的方法。如果这不起作用,我可能会尝试展示(并立即关闭)一个透明(或非常小的)视图控制器。
  • 毫无疑问。只是想让未来的人知道,以防他们偶然发现。没有downvote或任何东西。疯了,这还没有弄清楚。
【解决方案2】:

这对我有用

_ = navigationController.view.snapshotView(afterScreenUpdates: true)

【讨论】:

    【解决方案3】:
    UIButton *leftbtn  = [UIButton buttonWithType:UIButtonTypeCustom] ;
    
    [leftbtn addTarget:self action:@selector(city:) forControlEvents:UIControlEventTouchUpInside];
    [leftbtn setImage:[UIImage imageNamed:@"location"] forState:UIControlStateNormal];
    leftbtn.contentHorizontalAlignment   = UIControlContentHorizontalAlignmentLeft;
    [leftbtn sizeToFit];
    self.citybtn = leftbtn;
    UIBarButtonItem* cityBtn =  [[UIBarButtonItem alloc] initWithCustomView:leftbtn];
    
    UIBarButtonItem *left_fixedSpaceBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
    left_fixedSpaceBarButtonItem.width = -17;
    self.navigationItem.leftBarButtonItems = @[left_fixedSpaceBarButtonItem,cityBtn];
    

    …………

    当你改变时

    [self.citybtn setTitle:city forState:UIControlStateNormal];

    [self.citybtn sizeToFit];

    【讨论】:

    • 您的答案不明确,格式错误。请阅读how to answer 并进行相应编辑。
    【解决方案4】:

    一个解决方案是有一个函数,它通过删除/隐藏后退按钮并使用navigationItem.leftBarButtonItem 属性在其位置显示自定义 UIBarButtonItem 来完全更改 UIBarButtonItem。当然不理想,但按钮并不意味着在 VC 生命周期中更改,所以我想你可以试试。从这个意义上说,没有“正确”的方式,因为这不被视为标准行为。

    当我将此功能添加到示例视图控制器上的按钮时,它对我有用:

    func changeBackButton() {
        navigationItem.hidesBackButton = true
        navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Test", style: .plain, target: self, action: #selector(test))
    }
    

    【讨论】:

    • 但是后退箭头呢?它不见了?
    • @MJQZ1347 只需在标题中添加“stackoverflow.com/a/18874211/6597361 但无论哪种方式,这都是摆脱你处境的一种非常简单的方法
    • 不幸的是,滑动返回不再适用于该解决方法。还必须有一种更简单的方法来刷新导航栏而不弹出 VC?
    • @MJQZ1347 我自己刚刚浏览了stackoverflow,除了你已经提到的之外,我找不到另一种刷新方式,几分钟前我也尝试了一些方法;关于我的回答——虽然可以很容易地恢复向左滑动,但是如果您在布局中广泛使用 IB,那么它就不是很整洁;但正如我从一开始所说的那样,不应该发生完全刷新 - 只改变 tintColor 等。
    • 是的,可能。请查看我更新的问题,可能有更好的解决方法来刷新导航栏。
    猜你喜欢
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 2018-10-09
    • 2021-11-23
    • 2017-08-22
    • 1970-01-01
    • 1970-01-01
    • 2012-03-28
    相关资源
    最近更新 更多