49

我正在使用以下代码将两个按钮添加到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;

欣赏任何提示或想法。

4

15 回答 15

55

2015 年 7 月更新

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

相关问题

在 iOS 5 中使用 Storyboard 时无法将多个按钮分配给 UINavigationItem

如何在 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 是最需要考虑使用此技术的。

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

于 2014-03-30T09:23:06.760 回答
48

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

示例代码:

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
}
于 2019-01-11T07:59:07.040 回答
15

第一的:

因为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]
于 2018-11-12T09:54:55.273 回答
15

斯威夫特 5

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

let stackViewAppearance = UIStackView.appearance(whenContainedInInstancesOf: [UINavigationBar.self])
stackViewAppearance.spacing = -10
于 2020-11-24T14:18:08.480 回答
6

只需一行代码即可减少导航栏中按钮之间的空间:

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

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

于 2021-04-26T07:31:06.347 回答
5

如果您希望在右上角有 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 ]
于 2015-11-11T21:50:32.500 回答
4

这个答案可能有点晚了,但是这可以帮助最新的 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)

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

于 2017-05-17T14:24:49.963 回答
4

我的情况是给右边缘的 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
    }
于 2015-11-19T08:09:50.410 回答
3

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

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

于 2018-01-21T21:00:00.450 回答
2

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

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

于 2014-03-30T08:23:17.627 回答
1

另一个答案:它适用于 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)
}
于 2018-11-08T09:00:30.013 回答
1

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

于 2015-10-04T23:08:23.710 回答
0

我放弃了与这个错误作斗争,并提出了以下扩展:

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))
        }
    }
}
于 2017-06-21T16:05:49.403 回答
0

发现了一个可行的疯狂想法。

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写的,这个概念也很清楚。

于 2015-11-06T08:57:28.133 回答
0

斯威夫特 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)
于 2019-10-26T04:43:02.783 回答