【问题标题】:How to adjust space between two UIBarButtonItem in rightBarButtonItems如何调整rightBarButtonItems中两个UIBarButtonItem之间的空间
【发布时间】:2014-05-09 15:01:50
【问题描述】:

我正在使用下面的代码在self.navigationItem.rightBarButtonItems中添加两个按钮,我认为在iOS7中,两个按钮之间的空间太宽了,有没有办法减少这两个按钮之间的空间?

UIBarButtonItem *saveStyleButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"save.png"] style:UIBarButtonItemStyleBordered target:self action:@selector(saveStyle)];

UIBarButtonItem *shareStyleButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(shareStyle)];

NSArray *arr= [[NSArray alloc] initWithObjects:shareStyleButton,saveStyleButton,nil];

self.navigationItem.rightBarButtonItems=arr;

欣赏任何提示或想法。

【问题讨论】:

    标签: iphone xcode ios7 spacing rightbarbuttonitem


    【解决方案1】:

    2015 年 7 月更新

    更好的方法是使用故事板(在 Xcode 6.4 中测试)。首先,添加一个 UINavigationItem;其次,添加一个Bar Button Item;第三,为您刚刚在步骤 2 中创建的 Bar Button Item 添加一个视图;第四,在刚刚拖入的视图中添加任意数量的按钮;最后,用鼠标和约束调整空间。

    相关问题

    Can't assign multiple Buttons to UINavigationItem when using Storyboard with iOS 5

    How to add buttons to navigation controller visible after segueing?


    旧答案(仅适用于小插图)

    使用 imageInsets 属性:

    leftButton.imageInsets = UIEdgeInsetsMake(0.0, 0.0, 0, -15);
    rightButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, 0);
    

    对于三个或更多按钮,中间的两个都插入:

    leftButton.imageInsets = UIEdgeInsetsMake(0.0, 0.0, 0, -15);
    middleButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, -15);
    rightButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, 0);
    

    对于右侧按钮,请注意:项目数组中的第一个按钮是右侧按钮:

    rightButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, 0);
    middleButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, -15);
    leftButton.imageInsets = UIEdgeInsetsMake(0.0, 0.0, 0, -15);
    

    重要提示:在两个邻居之间拆分插图;如果将整个插图应用到一个边缘,很明显按钮在“空白”空间中重叠 - 一个按钮获得所有“间隙”触摸。即使像这样“拆分”调整,在两边的-40处,点击有时肯定会转到错误的按钮。 -15 或 -20 是最值得考虑的技术。

    通过应用这种方法,按钮甚至可以向四个方向移动。

    【讨论】:

    • 虽然这会移动图像,但不会移动可点击区域。
    • 要保留您想要编辑左右 UIBarButtonItem 上的 imageInsets 的可点击区域,如下所示:firstButton.imageInsets = UIEdgeInsetsMake(0, 0, 0, -25); secondButton.imageInsets = UIEdgeInsetsMake(0, -25, 0, 0);
    • 尝试了负插图,视觉效果调整得当;但是,点击不准确。例如。如果您有 3 个按钮并使用 imageInsets 使间距更紧,则点击按钮不会映射到实际按钮。
    • 它与 Storyboard 和 UIBarbuttonItem 与 customView 完美配合
    • FWIW:旧方法,negativeInsets,对于较小的值(例如 -10)是一种可以容忍的 hack,但对于较大的值,您很快就会发现按钮实际上是重叠的:其中一个按钮是“在前面",然后在重叠区域的任意位置点击。我之所以提到这一点,是因为如果只需要一点点调整,在代码中设置negativeInset 很容易,所以很诱人——只是不要调整得太远。
    【解决方案2】:

    我的解决方案是为右栏按钮使用自定义视图。 创建一个等间距的水平堆栈视图,并添加任意数量的按钮作为子视图。

    示例代码:

    func addRightBarButtonItems()
    {
        let btnSearch = UIButton.init(type: .custom)
        btnSearch.setImage(UIImage(systemName: "magnifyingglass"), for: .normal)
        btnSearch.addTarget(self, action: #selector(MyPageContainerViewController.searchButtonPressed), for: .touchUpInside)
        
        let btnEdit = UIButton.init(type: .custom)
        btnEdit.setImage(UIImage(systemName: "pencil"), for: .normal)
        btnEdit.addTarget(self, action: #selector(MyPageContainerViewController.editButtonPressed), for: .touchUpInside)
        
        let stackview = UIStackView.init(arrangedSubviews: [btnEdit, btnSearch])
        stackview.distribution = .equalSpacing
        stackview.axis = .horizontal
        stackview.alignment = .center
        stackview.spacing = 8
        
        let rightBarButton = UIBarButtonItem(customView: stackview)
        self.navigationItem.rightBarButtonItem = rightBarButton
    }
    

    【讨论】:

    • 这对我有用,但为了让它们彼此真正靠近我设置:stackview.spacing = 0
    • 非常好的解决方案...!谢谢...!
    • 你好,新手,那按钮的高宽怎么设置呢?
    【解决方案3】:

    斯威夫特 5

    在您的 AppDelegate 中添加以下代码:

    let stackViewAppearance = UIStackView.appearance(whenContainedInInstancesOf: [UINavigationBar.self])
    stackViewAppearance.spacing = -10
    

    【讨论】:

      【解决方案4】:

      第一:

      对于UIBarButtonItem,你必须使用构造函数init(customView: UIView)

      第二:

      使用fixedSpace 设置按钮之间的空间

      示例:

      let firstButton = UIButton()
      let firstButtonItem = UIBarButtonItem(customView: firstButton)
      
      let secondButton = UIButton()
      let secondButtonItem = UIBarButtonItem(customView: secondButton)
      
      let space = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
      space.width = WIDTH
      
      self.navigationItem.rightBarButtonItems = [firstButtonItem, space, secondButtonItem]
      

      【讨论】:

      • 这是一个很好的解决方案。但是,如果视图控制器的title 太大,则忽略此间距。
      【解决方案5】:

      只需要一行代码就可以减少导航栏中按钮之间的间距:

      UIStackView.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).spacing = -10
      

      在将按钮添加到导航栏之前,您必须将此行放在代码中。

      【讨论】:

        【解决方案6】:

        如果您希望右上角有 2 个按钮,它们之间或右侧没有空格,这对我有用。

        let imgLeft = UIImage(named: "buttonLeft")?.imageWithRenderingMode(.AlwaysOriginal)
        let bLeft = UIBarButtonItem(image: imgLeft, style: UIBarButtonItemStyle.Done, target: self, action: "action1:")
        let space = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
        space.width = -16.0
        
        bLeft.imageInsets = UIEdgeInsetsMake(0, 0, 0, -25.0)
        
        
        let imgRight = UIImage(named: "buttonRight")?.imageWithRenderingMode(.AlwaysOriginal)
        let bRight = UIBarButtonItem(image: imgRight, style: UIBarButtonItemStyle.Done, target: self, action: "action2:")
        
        bRight.imageInsets = UIEdgeInsetsMake(0, -25, 0, 0)
        
        
        self.navigationItem.rightBarButtonItems = [space,bLeft,bRight ]
        

        【讨论】:

          【解决方案7】:

          我的情况是在右侧边缘为 logOut 按钮提供水平空间。

           func addLogOutButtonToNavigationBar(triggerToMethodName: String)
              {
                  let button: UIButton = UIButton()
                  button.setImage(UIImage(named: "logOff.png"), forState: .Normal)
                  button.frame = CGRectMake(20, 0, 30, 25)
                  button.contentEdgeInsets = UIEdgeInsets.init(top: 0, left: 10, bottom: 0, right: -10)
          
                  button .addTarget(self, action:Selector(triggerToMethodName), forControlEvents: UIControlEvents.TouchUpInside)
                  let rightItem:UIBarButtonItem = UIBarButtonItem()
                  rightItem.customView = button
                  self.navigationItem.rightBarButtonItem = rightItem
              }
          

          【讨论】:

            【解决方案8】:

            这个答案可能有点晚了,但是这可以帮助最新的 IOS+Swift 组合(在我的例子中是 IOS 10 和 Swift 3)。在这里,我描述了如何为 rightBarButtonItems/leftBarButtonItems 向右/向左移动项目的一般方法:

            我们在这里用来移动 barButtonItem 的属性是 "imageEdgeInsets" 。那么,这里如何使用这个属性 -

            yourBarButtonItem.imageEdgeInsets = UIEdgeInsetsMake(top, left, bottom, right)

            这些顶部、左侧、底部、右侧是 CGFloat 类型,它们基本上是边距值,可以将您的项目相互推挤。 为了减少空格,我们可以只使用减号 (-) 像“-10”这样的值。

            因此,例如,如果我们想将其用于一组 leftBatButtonItems 并说,如果我们想将一个项目移动到右边一点,那么我们可以这样做 -

            ourBarButtonItem.imageEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, -15)
            

            我希望我们在这里得到大致的想法并希望它有所帮助:)

            【讨论】:

              【解决方案9】:

              没有任何代码。我只是在情节提要中需要间距的按钮之间放置了另一个 UIBarButtonItem。该按钮只是间距的占位符,UIBarButton 应该将 UIView 作为 UIBarButtonItem 的子视图。根据您的间距调整视图的宽度。请参阅屏幕截图。

              【讨论】:

                【解决方案10】:

                创建一个UIBarButtonItem,类型为灵活或固定空间。设置宽度并将其添加到 barbuttonitems 数组中。尝试使用负宽度,看看是否可行。

                或者,您可以调整图像。我认为系统按钮的大小是固定的,并且可能包含一些透明的部分,所以即使打包在一起,它们看起来仍然是间隔开的。

                【讨论】:

                • 两种都试过了,但都不管用。似乎有一个无法覆盖的最小值。
                • 也许可以尝试使用自定义视图,看看您可以使自定义视图变得多小,以确定是否有下限。我猜系统的那些就像它们一样并且几乎是不可变的(除非你可能会破解某些东西)。
                • 天哪,我自己用一行代码就解决了!
                • 代码为 saveStyleButton.imageInsets = UIEdgeInsetsMake(0.0, 0.0, 0, -50);
                • 我认为通过应用这种方法,按钮甚至可以在四个方向上移动!多加分啊!
                【解决方案11】:

                要在代码中完成此操作而不添加额外的容器视图,请使用UIBarButtonItem 并将系统项类型设置为FixedSpace。然后将固定空间的宽度设置为-10,放在两个按钮之间。

                【讨论】:

                • 在 iOS 10.2 上尝试:宽度的正值起作用,相邻按钮相距较远,但负值与零值具有相同的结果:相邻按钮位于相同的位置,就好像 FixedSpace 间隔不在那里。我怀疑他们已经取消了这种重叠项目的能力。
                • 如果数字是正数,这适用于 swift 4。
                【解决方案12】:

                另一个答案: 它适用于 ios 9 - 12。 您应该在函数 viewDidAppear(_ animated: Bool)viewDidLayoutSubviews() 中调用 fixNavigationItemsMargin(margin:)fixNavigationItemsMargin(margin:) 会修改 UINavigationController 堆栈。

                你可以在 BaseNavigationController 中调用 fixNavigationItemsMargin(margin:) ,做共同的工作。并在 UIViewController 中调用 fixNavigationItemsMargin(margin:) 进行精确布局。

                // do common initilizer
                class BaseNavigationController: UINavigationController {
                    override func viewDidLayoutSubviews() {
                        super.viewDidLayoutSubviews()
                        fixNavigationItemsMargin()
                    }
                
                    override func viewDidAppear(_ animated: Bool) {
                        super.viewDidAppear(animated)
                        fixNavigationItemsMargin()
                    }
                
                }
                
                extension UINavigationController {
                func fixNavigationItemsMargin(_ margin: CGFloat = 8) {
                    let systemMajorVersion = ProcessInfo.processInfo.operatingSystemVersion.majorVersion
                    if systemMajorVersion >= 11 {
                        // iOS >= 11
                        guard let contentView = navigationBar.subviews
                            .first(
                                where: { sub in
                                    String(describing: sub).contains("ContentView")
                            }) else { return }
                
                        // refer to: https://www.matrixprojects.net/p/uibarbuttonitem-ios11/
                        // if rightBarButtonItems has not any custom views, then margin would be 8(320|375)/12(414)
                        // should use customView
                        let needAdjustRightItems: Bool
                        if let currentVC = viewControllers.last,
                            let rightItems = currentVC.navigationItem.rightBarButtonItems,
                            rightItems.count > 0,
                            rightItems.filter({ $0.customView != nil }).count > 0 {
                            needAdjustRightItems = true
                        } else {
                            print("Use 8(320|375)/12(414), if need precious margin ,use UIBarButtonItem(customView:)!!!")
                            needAdjustRightItems = false
                        }
                
                        let needAdjustLeftItems: Bool
                        if let currentVC = viewControllers.last,
                            let leftItems = currentVC.navigationItem.leftBarButtonItems,
                            leftItems.count > 0,
                            leftItems.filter({ $0.customView != nil }).count > 0 {
                            needAdjustLeftItems = true
                        } else {
                            print("Use 8(320|375)/12(414), if need precious margin ,use UIBarButtonItem(customView:)!!!")
                            needAdjustLeftItems = false
                        }
                
                        let layoutMargins: UIEdgeInsets
                        if #available(iOS 11.0, *) {
                            let directionInsets = contentView.directionalLayoutMargins
                            layoutMargins = UIEdgeInsets(
                                top: directionInsets.top,
                                left: directionInsets.leading,
                                bottom: directionInsets.bottom,
                                right: directionInsets.trailing)
                        } else {
                            layoutMargins = contentView.layoutMargins
                        }
                
                        contentView.constraints.forEach(
                            { cst in
                
                                // iOS 11 the distance between rightest item and NavigationBar should be  margin
                                // rightStackView trailing space is -margin / 2
                                // rightestItem trailing to rightStackView trailing is -margin / 2
                                let rightConstant = -margin / 2
                
                                switch (cst.firstAttribute, cst.secondAttribute) {
                                case (.leading, .leading), (.trailing, .trailing):
                
                                    if let stackView = cst.firstItem as? UIStackView,
                                        stackView.frame.minX < navigationBar.frame.midX {
                                        // is leftItems
                                        if needAdjustLeftItems {
                                            cst.constant = margin - layoutMargins.left
                                        }
                                    } else if let layoutGuide = cst.firstItem as? UILayoutGuide,
                                        layoutGuide.layoutFrame.minX < navigationBar.frame.midX {
                                        // is leftItems
                                        if needAdjustLeftItems {
                                            cst.constant = margin - layoutMargins.left
                                        }
                                    }
                
                                    if let stackView = cst.firstItem as? UIStackView,
                                        stackView.frame.maxX > navigationBar.frame.midX {
                                        // is rightItems
                                        if needAdjustRightItems {
                                            cst.constant = rightConstant
                                        }
                                    } else if let layoutGuide = cst.firstItem as? UILayoutGuide,
                                        layoutGuide.layoutFrame.maxX > navigationBar.frame.midX {
                                        // is rightItems
                                        if needAdjustRightItems {
                                            cst.constant = rightConstant
                                        }
                                    }
                
                                default: break
                                }
                
                        })
                
                        // ensure items space == 8, minispcae
                        contentView.subviews.forEach(
                            { subsub in
                                guard subsub is UIStackView else { return }
                                subsub.constraints.forEach(
                                    { cst in
                                        guard cst.firstAttribute == .width
                                            || cst.secondAttribute == .width
                                            else { return }
                                        cst.constant = 0
                                })
                        })
                
                    } else {
                        // iOS < 11
                
                        let versionItemsCount: Int
                        if systemMajorVersion == 10 {
                            // iOS 10 navigationItem.rightBarButtonItems == 0
                            // space = 16(320|375) / 20(414)
                            // should adjust margin
                            versionItemsCount = 0
                        } else {
                            // iOS 9 navigationItem.rightBarButtonItems == 0
                            // space = 8(320|375) / 12(414)
                            // should not adjust margin
                            versionItemsCount = 1
                        }
                
                        let spaceProducer = { () -> UIBarButtonItem in
                            let spaceItem = UIBarButtonItem(
                                barButtonSystemItem: .fixedSpace,
                                target: nil,
                                action: nil)
                            spaceItem.width = margin - 16
                            return spaceItem
                        }
                        if let currentVC = viewControllers.last,
                            var rightItems = currentVC.navigationItem.rightBarButtonItems,
                            rightItems.count > versionItemsCount,
                            let first = rightItems.first {
                
                            // ensure the first BarButtonItem is NOT fixedSpace
                            if first.title == nil && first.image == nil && first.customView == nil {
                                print("rightBarButtonItems SPACE SETTED!!!  SPACE: ", abs(first.width))
                
                            } else {
                                rightItems.insert(spaceProducer(), at: 0)
                
                                // arranged right -> left
                                currentVC.navigationItem.rightBarButtonItems = rightItems
                            }
                        }
                
                        if let currentVC = viewControllers.last,
                            var leftItems = currentVC.navigationItem.leftBarButtonItems,
                            leftItems.count > versionItemsCount,
                            let first = leftItems.first {
                            if first.title == nil && first.image == nil && first.customView == nil {
                                print("leftBarButtonItems  SPACE SETTED!!!  SPACE: ", abs(first.width))
                            } else {
                                leftItems.insert(spaceProducer(), at: 0)
                
                                // arranged left -> right
                                currentVC.navigationItem.leftBarButtonItems = leftItems
                            }
                        }
                    }
                }
                }
                
                // do precise layout
                class ViewController: UIViewController {
                  override func viewDidLayoutSubviews() {
                    super.viewDidLayoutSubviews()
                    navigationController?.fixNavigationItemsMargin(40)
                }
                
                override func viewDidAppear(_ animated: Bool) {
                    super.viewDidAppear(animated)
                    navigationController?.fixNavigationItemsMargin(40)
                }
                

                【讨论】:

                • 这太完美了!这次真是万分感谢。当项目有如此多的自定义导航栏设计时,像我这样经验丰富的 iOS 工程师在处理 iOS 中的后退按钮时遇到了这样的耻辱!尽管我不得不为不同的 iOS 版本使用此代码多次调整和测试我的实现。再次感谢。
                【解决方案13】:

                找到了一个可行的疯狂想法。

                func createCustomToolbar(items: [UIBarButtonItem]) -> UIToolbar
                {
                    // no spacing between bar buttons
                    let customToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: items.count*45, height: 44))
                    customToolbar.items = items
                    customToolbar.barStyle = UIBarStyle(rawValue: -1)!
                    customToolbar.clearsContextBeforeDrawing = false
                    customToolbar.backgroundColor = UIColor.clearColor()
                    customToolbar.tintColor = UIColor.clearColor()
                    customToolbar.translucent = true
                    return customToolbar
                }
                
                
                let customToolbar = createCustomToolbar([item0,item1,item2,item3])
                navigationItem.rightBarButtonItems = [UIBarButtonItem(customView: customToolbar)]
                

                在 iOS7 及更高版本上测试。即使这是用swift写的,概念也很清楚。

                【讨论】:

                • 如何在这些按钮之间添加一些空间?
                【解决方案14】:

                我放弃了解决这个错误,并提出了以下扩展:

                import UIKit
                
                extension UIBarButtonItem {
                
                    convenience init(buttonImage: UIImage?, target: Any?, action: Selector?) {
                        let button = UIButton(type: .system)
                        button.frame = CGRect(origin: CGPoint.zero, size: buttonImage != nil ? buttonImage!.size : CGSize.zero)
                        button.setImage(buttonImage, for: .normal)
                
                        if let action = action {
                            button.addTarget(target, action: action, for: .touchUpInside)
                        }
                
                        self.init(customView: button)
                    }
                
                    public func updateButton(image: UIImage?) {
                        if let button = self.customView as? UIButton {
                            button.setImage(image, for: .normal)
                
                            let size = image != nil ? image!.size : CGSize.zero
                            let frame = button.frame
                            button.frame = frame.insetBy(dx: ceil((frame.size.width - size.width) / 2), dy: ceil((frame.size.height - size.height) / 2))
                        }
                    }
                }
                

                【讨论】:

                  【解决方案15】:

                  斯威夫特 5

                  如果您想在两个 Bar Button 项之间添加空间,然后在它们之间添加一个灵活空间,两个按钮将被推到左右边缘,因为灵活空间扩展以占据大部分工具栏。

                  例如:

                  let toolBar = UIToolbar()
                  
                  var items = [UIBarButtonItem]()
                  
                  let backBarButton =  UIBarButtonItem(image: UIImage(named: "icon-back.png"), style: .done, target: self, action: #selector(backButtonTapped))
                  
                  let nextBarButton =  UIBarButtonItem(image: UIImage(named: "icon-next.png"), style: .done, target: self, action: #selector(nextButtonTapped))
                  
                  let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
                  
                  items.append(backBarButton)
                  items.append(spacer)
                  items.append(nextBarButton)
                  
                  toolBar.setItems(items, animated: true)
                  

                  【讨论】:

                    猜你喜欢
                    • 2020-10-18
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-10-31
                    • 1970-01-01
                    • 2014-07-23
                    • 2018-04-26
                    • 2023-04-06
                    • 1970-01-01
                    相关资源
                    最近更新 更多