UINavigationBar 使用灵活的空间来均匀分布栏按钮项

Posted

技术标签:

【中文标题】UINavigationBar 使用灵活的空间来均匀分布栏按钮项【英文标题】:UINavigationBar using flexible spaces to distribute bar button items evenly 【发布时间】:2021-03-27 01:03:12 【问题描述】:

在基于 UINavigationController 的应用中,导航控制器的工具栏被打开,因此 UINavigationBar 在顶部,UIToolbar 在底部。

对于根视图控制器,显然没有返回按钮,也没有标题(也没有标题视图)。我已经设置了title = nil

同样的根视图控制器在导航栏的rightBarButtonItems 中有很多条形按钮项。由于除了这些项目之外导航栏中没有其他内容,我希望它们在导航栏中居中并均匀分布。这样,它们看起来不那么拥挤,不太可能触摸错误的按钮,总体上看起来更漂亮,并且也与底部工具栏的外观相匹配。

在底部工具栏中,这很容易通过在每个项目之间使用灵活的空间来实现(在我的例子中,在第一个/最后一个项目之前/之后)。

对于顶部导航栏,灵活空间(和固定空间)似乎被忽略了。

当导航栏上没有其他内容时,如何让导航栏中的栏按钮项分布在整个栏上?

或者是隐藏栏的唯一选项,实际上在顶部放置一个独立的工具栏? (不得不求助于这个将是一种耻辱,因为导航栏已经在那里并且几乎可以完成工作并且是自动管理的。)

【问题讨论】:

基本上,您无法控制在导航栏中放置东西的位置。值得为此提交增强请求。您最好的选择可能是用作标题视图的自定义视图,其中包含您的按钮;然后你在某种程度上负责内部布局。但即便如此,您也无法获得真正的控制权;这是一个偶然的事情。 我曾考虑使用自定义标题视图。但这意味着在 UINavigationBar 中使用 UIToolbar,这看起来有点疯狂。我想我可能只需要隐藏导航栏并创建一个独立的工具栏。但我希望有更好的方法。 【参考方案1】:

以下是我在导航栏中使用灵活空间以均匀分隔所有栏按钮项的近似方法。

注意:就目前而言,它仅适用于带有图像的条形按钮项目。纯文本项目不起作用,因为它使用图像大小来确定项目的宽度。更新它以使用文本或文本/图像项目应该不会太难。

它的工作原理是将所有条形按钮项目中所有图像的总宽度相加,然后从条形的大小中减去它以获得剩余空间量。然后将其除以项目数(加一,因为我希望所有项目前后都有一个空格)并调整屏幕比例。

将此设置为新 FIXED 空间项的宽度。

重新添加项目,在每个项目之前、之间和之后使用新的固定空间。

    func updateNavbarItemSpacing(forBarWidth width: CGFloat) 
        guard let oldItems = navigationItem.leftBarButtonItems else  return 
        var nonSpaceItems: [UIBarButtonItem] = []
        var usedWidth: CGFloat = 0.0
        var itemCount:CGFloat = 0.0
        
        for item in oldItems 
            if let itemWidth = item.image?.size.width 
                usedWidth += itemWidth
                itemCount += 1
                nonSpaceItems.append(item)
            
        
        
        let spaceWidth = ( ( width - usedWidth) / itemCount + 1 ) / UIScreen.main.scale
        let fixedSpace = UIBarButtonItem.fixedSpace(spaceWidth)
        
        var newItems: Array<UIBarButtonItem> = [fixedSpace]
        
        for item in nonSpaceItems 
            newItems.append(item)
            newItems.append(fixedSpace)
        
        
        navigationItem.leftBarButtonItems = newItems
    

无论何时更新项目,以及导航栏大小发生变化,都应调用此函数。例如,不要忘记将它包含在视图控制器中:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) 
        super.viewWillTransition(to: size, with: coordinator)
        
        updateNavbarItemSpacing(forBarWidth: size.width)
    

目前在测试中运行良好。完美的肖像模式。但在 lasdcape 方向上,最后我得到了一点额外的空间。还没有弄清楚这一点。

【讨论】:

【参考方案2】:

我现在找到了一种更简单的方法来实现这一点。

这个版本只是在项目数之间划分可用空间。

减去 2 分似乎效果更好 - 没有这个,结果在拥挤的工具栏中就不那么令人愉悦了。我想这允许每个项目之间有很小的余量?

请注意,如果某些项目的文本/图像比其他项目宽,则每个项目之间的间距将不均匀。所以这种方法最适合宽度相近的物品。

func updateNavbarItemSpacing(forBarWidth barWidth: CGFloat) 
        guard let items = navigationItem.leftBarButtonItems  else  return 
        if items.count == 0  return 
        let itemWidth = barWidth / CGFloat(items.count) - 2
        for item in items 
            item.width = itemWidth
        
        
        navigationItem.leftBarButtonItems = items
    

设置navigationItem的左侧工具栏项后调用上述方法。

此外,为了在旋转设备时获得正确的行为,请在视图控制器中调用它:

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) 
        super.viewWillTransition(to: size, with: coordinator)
        
        updateNavbarItemSpacing(forBarWidth: size.width)
    

【讨论】:

以上是关于UINavigationBar 使用灵活的空间来均匀分布栏按钮项的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式在 UINavigationBar 下方的 UIToolbar 中添加 UISegmentedControl

带有 UIImage 的 UIBarButtonItem 太宽

UINavigationBar TitleView 带字幕

UINavigationBar 中的项目未填充屏幕宽度

如何在 UINavigationBar [iOS 7] 中编辑左、右 UIBarButtonItem 的空白

如何防止黑色背景出现在我的UINavigationBar中?