在UINavigationBar中更改UIBarButtonItem的位置

时间:2011-04-23 00:03:41

标签: iphone objective-c uinavigationbar uibarbuttonitem

如何在UINavigationBar中更改UIBarButtonItem的位置?我希望我的按钮比正常位置高5px。

21 个答案:

答案 0 :(得分:118)

此代码为UINavigationBar创建一个带有图像背景和自定义位置的后退按钮。诀窍是创建一个中间视图并修改其边界。

UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *backBtnImage = [UIImage imageNamed:@"btn-back"];
UIImage *backBtnImagePressed = [UIImage imageNamed:@"btn-back-pressed"];
[backBtn setBackgroundImage:backBtnImage forState:UIControlStateNormal];
[backBtn setBackgroundImage:backBtnImagePressed forState:UIControlStateHighlighted];
[backBtn addTarget:self action:@selector(goBack) forControlEvents:UIControlEventTouchUpInside];
backBtn.frame = CGRectMake(0, 0, 63, 33);
UIView *backButtonView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 63, 33)];
backButtonView.bounds = CGRectOffset(backButtonView.bounds, -14, -7);
[backButtonView addSubview:backBtn];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:backButtonView];
self.navigationItem.leftBarButtonItem = backButton;

答案 1 :(得分:37)

我使用转换和自定义视图解决了:

(SWIFT)

  // create the button
  let suggestImage  = UIImage(named: "tab-item-popcorn-on")!.imageWithRenderingMode(.AlwaysOriginal)
  let suggestButton = UIButton(frame: CGRectMake(0, 0, 40, 40))
  suggestButton.setBackgroundImage(suggestImage, forState: .Normal)
  suggestButton.addTarget(self, action: Selector("suggesMovie:"), forControlEvents:.TouchUpInside)

  // here where the magic happens, you can shift it where you like
  suggestButton.transform = CGAffineTransformMakeTranslation(10, 0)

  // add the button to a container, otherwise the transform will be ignored  
  let suggestButtonContainer = UIView(frame: suggestButton.frame)
  suggestButtonContainer.addSubview(suggestButton)
  let suggestButtonItem = UIBarButtonItem(customView: suggestButtonContainer)

  // add button shift to the side
  navigationItem.rightBarButtonItem = suggestButtonItem

答案 2 :(得分:34)

没有特别好的方法可以做到这一点。你最好的选择是你必须要继承UINavigationBar,并覆盖layoutSubviews来调用[super layoutSubviews],然后找到并重新定位按钮的视图。

答案 3 :(得分:17)

对于那些为iOS 5开发的人而言,他们偶然发现了这一点并且气馁...尝试这样的事情:

float my_offset_plus_or_minus = 3.0f;

UIBarButtonItem * item = [[UIBarButtonItem alloc] initWithTitle:@"title" 
                                                          style:UIBarButtonItemStyleDone
                                                          target:someObject action:@selector(someMessage)];

[item setBackgroundVerticalPositionAdjustment:my_offset_plus_or_minus forBarMetrics:UIBarMetricsDefault];

答案 4 :(得分:12)

最好的方法是将UINavigationBar子类化,如下所述:https://stackoverflow.com/a/17434530/1351190

以下是我的例子:

#define NAVIGATION_BTN_MARGIN 5

@implementation NewNavigationBar

- (void)layoutSubviews {

    [super layoutSubviews];

    UINavigationItem *navigationItem = [self topItem];

    UIView *subview = [[navigationItem rightBarButtonItem] customView];

    if (subview) {

        CGRect subviewFrame = subview.frame;
        subviewFrame.origin.x = self.frame.size.width - subview.frame.size.width - NAVIGATION_BTN_MARGIN;
        subviewFrame.origin.y = (self.frame.size.height - subview.frame.size.height) / 2;

        [subview setFrame:subviewFrame];
    }

    subview = [[navigationItem leftBarButtonItem] customView];

    if (subview) {

        CGRect subviewFrame = subview.frame;
        subviewFrame.origin.x = NAVIGATION_BTN_MARGIN;
        subviewFrame.origin.y = (self.frame.size.height - subview.frame.size.height) / 2;

        [subview setFrame:subviewFrame];
    }
}

@end

希望它有所帮助。

答案 5 :(得分:6)

尝试下面的代码,

UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Logout" style:UIBarButtonItemStyleDone target:self action:nil];
[button setBackgroundVerticalPositionAdjustment:-20.0f forBarMetrics:UIBarMetricsDefault];
[[self navigationItem] setRightBarButtonItem:button];

用于更改此代码中的“y”位置。根据您的要求更改“y”值(此处为-20.0f)。如果值为正,则按下按钮位置。如果值为负,则它将按下您的按钮位置。

答案 6 :(得分:6)

我需要将按钮设置为向右移动。这是我在Swift中使用UIAppearance的方法。那里还有垂直位置属性,所以我想你可以向任何方向调整。

UIBarButtonItem.appearance().setTitlePositionAdjustment(UIOffset.init(horizontal: 15, vertical: 0), forBarMetrics: UIBarMetrics.Default)

这对我来说似乎比直接搞乱框架或添加自定义子视图要小得多。

答案 7 :(得分:4)

如果您只是使用图像而不是默认的镶边,则可以使用负图像插图(在尺寸检查器中设置)在内部移动图像 UIBarButtonItem(方便,因为默认情况下)水平填充可能导致图像比您想要的更深入到内部。您也可以使用图像插入来将图像定位在UIBarButtonItem的边界之外,并且左侧按钮的整个附近都是可点击的,因此您不必担心确保它位于点击目标。 (至少在合理范围内。)

答案 8 :(得分:3)

我能找到的最佳解决方案是使用包含左/右额外空间的子视图初始化UIBarButtonItem。这样您就不必担心子类化,并且更改导航栏内其他元素的布局,例如标题。

例如,要移动按钮14指向左侧:

UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, image.size.width + 14, image.size.height)];
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(-14, 0, image.size.width, image.size.height);
[button setImage:image forState:UIControlStateNormal];
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
[containerView addSubview:button];

UIButton* button2 = [UIButton buttonWithType:UIButtonTypeCustom];
button2.frame = CGRectMake(0, 0, image.size.width + 14, image.size.height);
[button2 addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
[containerView addSubview:button2];

UIBarButtonItem* item = [[[self alloc] initWithCustomView:containerView] autorelease];

答案 9 :(得分:3)

  • Swift 3
  • 自定义导航栏高度
  • 没有标题跳跃

第1步: 使用Appearance API设置标题位置。例如,在AppDelegate的didFinishLaunchingWithOptions

UINavigationBar.appearance().setTitleVerticalPositionAdjustment(-7, for: .default)

第2步: 子类UINavigationBar

class YourNavigationBar: UINavigationBar {

    let YOUR_NAV_BAR_HEIGHT = 60

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        return CGSize(width: UIScreen.main.bounds.width, 
                     height: YOUR_NAV_BAR_HEIGHT)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        let navigationItem = self.topItem

        for subview in subviews {
            if  subview == navigationItem?.leftBarButtonItem?.customView ||
                subview == navigationItem?.rightBarButtonItem?.customView {
                subview.center = CGPoint(x: subview.center.x, y: YOUR_NAV_BAR_HEIGHT / 2)
            }
        }
    }
}

答案 10 :(得分:2)

就我而言

  1. 更改barbuttonItem的框架以自定义空格

  2. 动态添加,删除barButtonItems。

  3. 通过tableview的contentOffset.y更改色彩颜色

  4. 像这样 enter image description here enter image description here

    enter image description here enter image description here

    如果您的最低目标是iOS 11,则可以更改viewDidLayoutSubviews中的barButton帧

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        // Change the navigationBar item frames
        if let customView = wishButton.customView?.superview {
            customView.transform = CGAffineTransform(translationX: 7.0, y: 0)
        }
    
        if let customView = gourmetCountButton.customView?.superview {
            customView.transform = CGAffineTransform(translationX: 9.0, y: 0)
        }
    }
    

    但是,它只适用于iOS 11。

    我也尝试过使用fixedSpace。但它并没有在多个navigationBarButton项目中工作。

     let space = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
        space.width = -10
    

    因此,我更改了customView的宽度以调整水平空间。

    这是我的barButtonItem类之一

    final class DetailShareBarButtonItem: UIBarButtonItem {
    
    // MARK: - Value
    // MARK: Public
    ***// Change the width to adjust space***
    let button = UIButton(frame: CGRect(x: 0, y: 0, width: 32.0, height: 30.0))
    
    override var tintColor: UIColor? {
        didSet {
            button.tintColor = tintColor
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setButton()
    }
    
    required override init() {
        super.init()
        setButton()
    }
    
    
    // MARK: - Function
    // MARK: Private
    private func setButton() {
        // Button
        button.setImage( #imageLiteral(resourceName: "navibarIcShare02White").withRenderingMode(.alwaysTemplate), for: .normal)
        button.tintColor              = .white
        button.imageEdgeInsets        = UIEdgeInsetsMake(0, 1.0, 1.0, 0)
        button.imageView?.contentMode = .scaleAspectFill
    
        let containerView = UIView(frame: button.bounds)
        containerView.backgroundColor = .clear
        containerView.addSubview(button)
        customView = containerView
    }
    }
    

    这是结果。

    我在iOS 9~11上测试过,(Swift 4)

    enter image description here

答案 11 :(得分:2)

这是Adriano使用Swift 3的解决方案。这是唯一对我有用的解决方案,我试过了几个。

  let suggestImage  = UIImage(named: "menu.png")!
    let suggestButton = UIButton(frame: CGRect(x:0, y:0, width:34, height:20))
    suggestButton.setBackgroundImage(suggestImage, for: .normal)
    suggestButton.addTarget(self, action: #selector(self.showPopover(sender:)), for:.touchUpInside)
    suggestButton.transform = CGAffineTransform(translationX: 0, y: -8)
    // add the button to a container, otherwise the transform will be ignored
    let suggestButtonContainer = UIView(frame: suggestButton.frame)
    suggestButtonContainer.addSubview(suggestButton)
    let suggestButtonItem = UIBarButtonItem(customView: suggestButtonContainer)
    // add button shift to the side
    navigationItem.leftBarButtonItem = suggestButtonItem

答案 12 :(得分:2)

Swift 3.1

let cancelBarButtonItem = UIBarButtonItem()
cancelBarButtonItem.setBackgroundVerticalPositionAdjustment(4, for: .default)
vc.navigationItem.setLeftBarButton(cancelBarButtonItem, animated: true)

答案 13 :(得分:2)

正如@Anomie所说,我们需要子类UINavigationBar并覆盖layoutSubviews()

这会将所有正确的条形按钮项目牢固地附加到导航栏右侧(而不是默认情况下略微左侧调整)

class AdjustedNavigationBar: UINavigationBar {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let rightItems = topItem?.rightBarButtonItems where rightItems.count > 1 {
            for i in 0..<rightItems.count {
                let barButtonItem = rightItems[i]
                if let customView = barButtonItem.customView {
                    let frame = customView.frame
                    customView.frame = CGRect(x: UIApplication.sharedApplication().windows.last!.bounds.size.width-CGFloat(i+1)*44, y: frame.origin.y, width: frame.size.width, height: frame.size.height)
                }

            }
        }
    }
}

设置UINavigationController的UINavigationBar属性的唯一地方是它的init(),如下所示:

let controllerVC = UINavigationController(navigationBarClass: AdjustedNavigationBar.self, toolbarClass: nil)
controllerVC.viewControllers = [UIViewController()]

第二行设置UINavigationController的根视图控制器(因为我们无法通过init(rootViewController:)

进行设置

答案 14 :(得分:1)

您始终可以使用按钮上的“插入”进行调整。例如,

dbpath=/var/lib/mongodb

它对我有用。

答案 15 :(得分:1)

在自定义视图中使用自定义视图和重载UIBarButtonItem的初始layoutSubviews,如此

-(void) layoutSubviews {
  [super layoutSubviews];
  CGRect frame = self.frame;
  CGFloat offsetY = 5;
  frame.origin.y = (44 - frame.size.height) / 2 - offsetY;
  self.frame = frame;
}

答案 16 :(得分:0)

使用更改左栏位置和图像边缘插图的导航栏

迅捷4

let leftBarButtonItem = UIBarButtonItem.init(image: UIImage(named:"ic_nav-bar_back.png"), landscapeImagePhone: nil, style: .plain, target: viewController, action: #selector(viewController.buttonClick(_:)))
            leftBarButtonItem.imageInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0)
            leftBarButtonItem.tintColor = UIColor(hex: 0xED6E19)
            viewController.navigationItem.setLeftBarButton(leftBarButtonItem, animated: true)

答案 17 :(得分:0)

如果您只想像我一样调整自定义后退按钮的位置,则可以使用其中一种向UIImage本身添加插图的解决方案来实现。

我使用了https://www.simonbattersby.com/blog/browsers-and-fractional-pixels/

中的解决方案

添加此扩展功能

import UIKit

extension UIImage {
    func imageWithInsets(insets: UIEdgeInsets) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(
            CGSize(width: self.size.width + insets.left + insets.right,
                   height: self.size.height + insets.top + insets.bottom), false, self.scale)
        let _ = UIGraphicsGetCurrentContext()
        let origin = CGPoint(x: insets.left, y: insets.top)
        self.draw(at: origin)
        let imageWithInsets = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return imageWithInsets
    }
}

然后像自定义后退按钮一样使用

let backIcon = UIImage(named: "back_btn_icon")!.imageWithInsets(insets: UIEdgeInsets(top: 0, left: 0, bottom: 5, right: 0))
navigationController?.navigationBar.backIndicatorImage = backIcon
navigationController?.navigationBar.backIndicatorTransitionMaskImage = backIcon

根据需要调整插图

答案 18 :(得分:0)

仿射变换可以满足您的需求。在我的情况下,设计师给了我16x16的关闭图标,我想创建44x44的水龙头区域。

closeButton.transform = CGAffineTransform(translationX: (44-16)/2, y: 0)
closeButton.snp.makeConstraints { make in
   make.size.equalTo(CGSize(width: 44, height: 44))
}
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: closeButton)

答案 19 :(得分:0)

我通过在自定义按钮的图像边缘插入中进行调整找到了此问题的解决方案。我在应用程序中有要求增加导航栏的高度,并且在增加高度后使rightBarButtonItem和leftBarButtonItem图像处于未定位的问题。

找到以下代码: -

UIImage *image = [[UIImage imageNamed:@"searchbar.png"];
UIButton* searchbutton = [UIButton buttonWithType:UIButtonTypeCustom];
[searchbutton addTarget:self action:@selector(searchBar:) forControlEvents:UIControlEventTouchUpInside]; 
searchbutton.frame = CGRectMake(0,0,22, 22);
[searchbutton setImage:image forState:UIControlStateNormal];
[searchbutton setImageEdgeInsets:UIEdgeInsetsMake(-50, 0,50, 0)];
// Make BarButton Item
 UIBarButtonItem *navItem = [[UIBarButtonItem alloc] initWithCustomView:searchbutton];
self.navigationItem.rightBarButtonItem = navItem;

希望这有助于任何人。

答案 20 :(得分:0)

这是一个足以满足我需求的简单解决方法。我在UINavigationBar的右侧添加了一个信息按钮,但默认情况下它位于太靠近边缘的位置。通过扩展框架的宽度,我能够在右侧创建额外的间距。

 UIButton *info = [UIButton buttonWithType:UIButtonTypeInfoLight];
 CGRect frame = info.frame;
 frame.size.width += 20;
 info.frame = frame;
 myNavigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc]initWithCustomView:info]autorelease];