web-dev-qa-db-ja.com

rightBarButtonItemsの2つのUIBarButtonItem間のスペースを調整する方法

私は次のコードを使用してself.navigationItem.rightBarButtonItemsに2つのボタンを追加していますが、iOS7では2つのボタン間のスペースが広すぎると思いますが、これら2つのボタン間のスペースを減らす方法はありますか?

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;

ヒントやアイデアに感謝します。

32
Bob

2015年7月に更新

これを行うより良い方法は、ストーリーボード(Xcode 6.4でテスト済み)を使用することです。最初に、UINavigationItemを追加します。次に、Bar Button Itemを追加します。第三に、ステップ2で作成したばかりのBar Button Itemにビューを追加します。 4番目に、ドラッグしたばかりのビューに必要なだけボタンを追加します。最後に、マウスと制約でスペースを調整します。

関連する質問

iOS 5でStoryboardを使用する場合、複数のボタンをUINavigationItemに割り当てることはできません

セグエ後に表示されるナビゲーションコントローラーにボタンを追加する方法


古い回答(小さなインセットでのみ許容)

ImageInsetsプロパティを使用します。

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

3つ以上のボタンの場合、中央のボタンは両方のインセットを取得します。

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);

重要:インセットを2つの隣人の間で分割します。インセット全体を1つのEdgeに適用すると、ボタンが「空白」スペースで重なっていることが明らかになります。1つのボタンがすべての「ギャップ」タッチを取得します。このように調整を「分割」した場合でも、両端が-40の場合、タップが間違ったボタンに移動することがあります。 -15または-20は、この手法での使用を検討するのに最も適しています。

このメソッドを適用することにより、ボタンを4方向に動かすことさえできます。

48
Bob

私の解決策は、右のバーボタンにカスタムビューを使用することです。等間隔の水平スタックビューを作成し、任意の数のボタンをサブビューとして追加します。

サンプルコード:

func addRightBarButtonItems()
{
    let btnSearch = UIButton.init(type: .custom)
    btnSearch.setImage(UIImage(named: "icon-search"), for: .normal)
    btnSearch.addTarget(self, action: #selector(MyPageContainerViewController.searchButtonPressed), for: .touchUpInside)

    let btnEdit = UIButton.init(type: .custom)
    btnEdit.setImage(UIImage(named: "icon-edit"), 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
}
8
Ali Seymen

右上に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 ]
4
abinop

最初:

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]
4
ober

私の状況は、右端の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
    }
4
A.G

この回答には少し遅れる可能性がありますが、これは最新の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)

ここで一般的なアイデアを得て、それが役立つことを願っています:)

4
sahilabrar

タイプがフレキシブルまたは固定スペースのUIBarButtonItemを作成します。幅を設定し、barbuttonitemsの配列に追加します。負の幅を使用してみてください、それが機能するかどうかを確認してください。

または、画像を調整することもできます。システムボタンのサイズは固定されており、透明な部分が含まれている可能性があるため、一緒に梱包しても間隔が空いているように見えます。

2
Joride

コードなし。ストーリーボードのスペースを必要とするボタンの間に別のUIBarButtonItemを配置しました。ボタンは間隔の単なるプレースホルダーであり、UIBarButtonにはUIBarButtonItemのサブビューとしてUIViewが必要です。間隔に合わせてビューの幅を調整します。スクリーンショットを参照してください。

enter image description here

enter image description here

enter image description here

2
iOSCodeJunkie

追加のコンテナビューを追加せずにコードでこれを実現するには、UIBarButtonItemをシステムアイテムタイプをFixedSpaceに設定して使用します。次に、固定スペースの幅を-10に設定し、2つのボタンの間に配置します。

1
Alex311

別の答え:iOS 9-12で動作しますfixNavigationItemsMargin(margin:) in function viewDidAppear(_ animated:Bool) and viewDidLayoutSubviews()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)
}
1
Jules

機能するクレイジーなアイデアを見つけました。

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の概念は明確です。

0
Prcela

私はこのバグとの戦いをあきらめ、次の拡張を思いつきました。

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))
        }
    }
}
0
bteapot