如何调整UIToolBar左右填充

时间:2011-05-16 17:36:28

标签: iphone objective-c

我用代码创建一个UIToolbar,用界面构建器创建另一个UIToolbar。但是,发现两个工具栏有不同的左右填充,如下所示:

来自Interface Builder:

enter image description here

来自代码:

enter image description here

UIImage *buttonImage = [[UIImage imageNamed:@"button.png"] stretchableImageWithLeftCapWidth:10 topCapHeight:0];
UIButton *btnTest = [UIButton buttonWithType:UIButtonTypeCustom];
[btnTest setBackgroundImage:buttonImage forState:UIControlStateNormal];
[btnTest setTitle:@"Back" forState:UIControlStateNormal];   
[btnTest.titleLabel setFont:[UIFont boldSystemFontOfSize:13]];  
[btnTest setBackgroundImage:[imgToolbarButton stretchableImageWithLeftCapWidth:5 topCapHeight:0]  forState:UIControlStateNormal];
[btnTest addTarget:self action:@selector(clearDateEdit:) forControlEvents:UIControlEventTouchUpInside];
btnTest.frame = CGRectMake(0.0, 0.0, 50, 30);
UIBarButtonItem *btnTestItem = [[UIBarButtonItem alloc] initWithCustomView:btnTest];
[self.toolbar setItems:[NSArray arrayWithObjects:btnTestItem,nil]];
[btnTestItem release];

我的问题是如何通过代码调整UIToolbar的左右填充?

更新

我发现这个对齐问题只发生在使用UIButton的customView的UIBarButtonItem上,UIBarButtonItem对齐很好。知道是什么导致这个或解决这个问题。

我现在能想到的唯一解决方案是手动设置框架。

11 个答案:

答案 0 :(得分:148)

我遇到了同样的问题,你可以使用UIBarButtonSystemItemFixedSpace做一个巧妙的技巧,在第一个按钮之前和最后一个按钮之后添加一个负宽度,然后将按钮移到边缘。

例如,要删除右边距,请将以下FixedSpace条形项添加为最后一项:

UIBarButtonItem *negativeSeparator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
negativeSeparator.width = -12;

左右边距为12px。

iOS7更新 - iPhone的利润率为16px,iPad的利润率为20px!

答案 1 :(得分:23)

iOS 11之前

您有三种可能的解决方案:

  • 第一个是使用固定的空格项UIBarButtonItem(barButtonSystemItem:.fixedSpace ...),负宽度
  • 另一个是覆盖自定义视图
  • 上的alignmentRectInsets
  • 最后一个,如果您使用UIButton作为项目的自定义视图,则可以覆盖contentEdgeInsets和hitTest(_:with :)

当然,第一种解决方案似乎比其他解决方案更好

UIBarButtonItem *negativeSeparator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
negativeSeparator.width = -12;

如果您使用swift,代码将如下所示

var negativeSeparator = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
negativeSeparator.width = -12

iOS 11之后(包含iOS 11)

不幸的是,所有解决方案都无法在iOS 11中使用

  • 第一个解决方案:设置负宽度不再有效
  • 第二个解决方案:覆盖alignmentRectInsets将导致部分项目不再接收触摸
  • 最后一个解决方案:我认为覆盖hitTest(_:with :)不是一个好主意,请不要这样做!

您还可以在Developer Forums上看到一些建议,但在查看完所有评论之后,您会发现有关此主题的建议是创建自定义UINavigationBar子类并执行复杂的操作。

天啊,我想做的就是改变填充,而不是导航栏!

幸运的是,我们可以在iOS 11中使用技巧来做到这一点!

我们走了:

1。创建自定义按钮

  • 将translatesAutoresizingMaskIntoConstraints设置为false
  • 覆盖alignmentRectInsets
    • 右侧的项目使用UIEdgeInsets(顶部:0,左:-8,底部:0,右:8)
    • 左侧的
    • 项目使用UIEdgeInsets(顶部:0,左:8,底部:0,右:-8)
        

      如果你不了解alignmentRectInsets,你可以先阅读 this blog

swift version

var customButton = UIButton(type: .custom)
customButton.overrideAlignmentRectInsets = UIEdgeInsets(top: 0, left: x, bottom: 0, right: -x) // you should do this in your own custom class
customButton.translatesAutoresizingMaskIntoConstraints = false;

objective-c version

UIButton *customButton = [UIButton buttonWithType:UIButtonTypeCustom];
customButton.overrideAlignmentRectInsets = UIEdgeInsetsMake(0, x, 0, -x); // you should do this in your own custom class
customButton.translatesAutoresizingMaskIntoConstraints = NO;

2。使用自定义按钮创建项目

swift version

var item = UIBarButtonItem(customView: customButton)

objective-c version

UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:customButton]

3。创建一个具有宽度

的fixedSpace类型UIBarButtonItem

设置值,而不是负值

swift version

var positiveSeparator = UIBarButtonItem(barButtonSystemItem:.fixedSpace, target: nil, action: nil)
positiveSeparator.width = 8

objective-c version

UIBarButtonItem *positiveSeparator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
positiveSeparator.width = 8;

4。将数组设置为leftitems或rightitems

fixedSpace类型UIBarButton项必须是数组中的第一个元素

swift version

self.navigationItem.leftBarButtonItems = [positiveSeparator, item, ...]

objective-c version

self.navigationItem.leftBarButtonItems = @{positiveSeparator, item, ...}

做得好

完成所有步骤后,您会看到填充变小,类型区域似乎正确!

如果您发现错误,请告诉我们! 我会尽力回答你的问题!

注意

在iOS 11之前,你应该关心设备的屏幕宽度;如果屏幕是5.5英寸,负片是-12磅,其他屏幕是-8pt。

如果你在iOS 11上使用我的解决方案,你不需要关心设备屏幕,只需设置8pt, 你应该关心项目在导航栏,左侧或右侧的位置,这会影响你的自定义视图的alignmentRectInsets

想要更多分区

如果您想承诺您的点击区域大于44 * 44,您可以覆盖以下方法

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    CGSize acturalSize = self.frame.size;
    CGSize minimumSize = kBarButtonMinimumTapAreaSize;
    CGFloat verticalMargin = acturalSize.height - minimumSize.height >= 0 ? 0 : ((minimumSize.height - acturalSize.height ) / 2);
    CGFloat horizontalMargin = acturalSize.width - minimumSize.width >= 0 ? 0 : ((minimumSize.width - acturalSize.width ) / 2);
    CGRect newArea = CGRectMake(self.bounds.origin.x - horizontalMargin, self.bounds.origin.y - verticalMargin, self.bounds.size.width + 2 * horizontalMargin, self.bounds.size.height + 2 * verticalMargin);
    return CGRectContainsPoint(newArea, point);
}

答案 2 :(得分:7)

这是一个很好的问题,即使提供了解决方案 - 它也无法解决iOS11上的问题。

工作解决方案

如果您创建了UIButton的新扩展程序:

class BarButton: UIButton {

    override var alignmentRectInsets: UIEdgeInsets {
        return UIEdgeInsetsMake(0, 16, 0, 16)
    }

}

然后当你在布局中使用它时:

lazy var btnLogin: BarButton = {
    let btn = BarButton(type: .custom)
    // Add your button settings

    btn.widthAnchor.constraint(equalToConstant: self.frame.size.width).isActive = true
    btn.heightAnchor.constraint(equalToConstant: 50).isActive = true
    btn.translatesAutoresizingMaskIntoConstraints = false
    return btn
}()

这解决了一个非常烦人的问题,如果你有任何问题请给我一个喊叫。

答案 3 :(得分:3)

使用此按钮

UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                                                                           target:nil
                                                                           action:nil];

答案 4 :(得分:2)

我遇到了同样的问题。最后,我通过继承UIToolbar并覆盖布局子视图方法解决了这个问题。

- (void)layoutSubviews {

  [super layoutSubviews];

  if (leftItem_ && leftItem_.customView
      && [leftItem_.customView isKindOfClass:[UIButton class]]) {
    CGRect newFrame = leftItem_.customView.frame;
    newFrame.origin.x = 0;   // reset the original point x to 0; default is 12, wired number
    leftItem_.customView.frame = newFrame;    
  }

  if (rightItem_ && rightItem_.customView
      && [rightItem_.customView isKindOfClass:[UIButton class]]) {
    CGRect newFrame = rightItem_.customView.frame;
    newFrame.origin.x = self.frame.size.width - CGRectGetWidth(newFrame);
    rightItem_.customView.frame = newFrame;
  }

}

答案 5 :(得分:2)

如果要使用customview(initWithCustomView),可以更改工具栏的偏移和宽度

[myToolBar setFrame:CGRectMake(-10, 0, [UIScreen mainScreen].bounds.size.width+10, 44)];

答案 6 :(得分:2)

当我试图将工具栏作为UIButton的子视图居中时,我偶然发现了这一点。由于工具栏需要宽度较小,因此最佳解决方案是每侧都有一个灵活的按钮:

UIBarButtonItem flexibleButtonItemLeft = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

UIBarButtonItem centeredButtonItem = ...

UIBarButtonItem flexibleButtonItemRight = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

UIToolbar toolbar = ...

toolbar.items = @[flexibleButtonItemLeft, centeredButtonItem, flexibleButtonItemRight];

答案 7 :(得分:0)

最后,为了为UIBarButtonItem定制背景图像并适应对齐,我放弃了UIBarButtonItem并手动添加了UIButton。

UIImage *buttonImage = [[UIImage imageNamed:@"button.png"] stretchableImageWithLeftCapWidth:10 topCapHeight:0];
UIButton *btnTest = [UIButton buttonWithType:UIButtonTypeCustom];
[btnTest setBackgroundImage:buttonImage forState:UIControlStateNormal];
[btnTest setTitle:@"Back" forState:UIControlStateNormal];   
[btnTest.titleLabel setFont:[UIFont boldSystemFontOfSize:13]];  
[btnTest setBackgroundImage:[imgToolbarButton stretchableImageWithLeftCapWidth:5 topCapHeight:0]  forState:UIControlStateNormal];
[btnTest addTarget:self action:@selector(clearDateEdit:) forControlEvents:UIControlEventTouchUpInside];
btnTest.frame = CGRectMake(0.0, 0.0, 50, 30);
[self.toolbar addSubview:btnTest];
[btnTestItem release];

答案 8 :(得分:0)

我认为一种棘手的方法是使用Aspects(或方法调配),如同吹嘘:

[UINavigationBar aspect_hookSelector:@selector(layoutSubviews) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> info){
        UINavigationBar *bar = info.instance;

        //[bar layoutSubviews];

        if ([bar isKindOfClass:[UINavigationBar class]]) {
            if (@available(iOS 11, *)) {
                bar.layoutMargins = UIEdgeInsetsZero;

                for (UIView *subview in bar.subviews) {
                    if ([NSStringFromClass([subview class]) containsString:@"ContentView"]) {
                        UIEdgeInsets oEdges = subview.layoutMargins;
                        subview.layoutMargins = UIEdgeInsetsMake(0, 0, 0, oEdges.right);
                    }
                }
            }
        }
    } error:nil];

答案 9 :(得分:0)

只需向您的UIToolbar前后约束中添加负常数。这样,工具栏在视图外部开始和结束,因此具有较少的填充。

答案 10 :(得分:0)

就我而言,我需要减少 leftBarButtonItem 的左侧填充并保持整个区域的触摸。

class FilterButton: Button {

override init() {
    super.init()
    setImage(UIImage(named: "filter"), for: .normal)
    backgroundColor = UIColor.App.ultraLightGray
    layer.cornerRadius = 10
    
    snp.makeConstraints {
        $0.size.equalTo(36)
    }
}

override var alignmentRectInsets: UIEdgeInsets {
    return UIEdgeInsets(top: 0, left: 4, bottom: 0, right: -4)
}
}


let filterButton = FilterButton()
filterButton.addTarget(self, action: #selector(filterTapped(_:)), for: .touchUpInside)
let filterBarButton = UIBarButtonItem(customView: filterButton)
let spacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
    
navigationItem.setLeftBarButtonItems([spacer, filterBarButton], animated: false)