自定义UIBarButtonItem对齐与iOS7

问题描述:

因此,我有许多其他人遇到与使用UIButton创建UIBarButtonItem作为自定义视图相同的问题。自定义UIBarButtonItem对齐与iOS7

基本上按钮大概是10个像素远左或右。当我使用没有自定义视图的常规BarButtonItem时,这不会发生。

这篇文章提供的部分解决方案: UIBarButton With Custom View

这里是我的代码,我通过继承的UIButton(如在其他职位说明)

- (UIEdgeInsets)alignmentRectInsets { 
    UIEdgeInsets insets; 
    if ([self isLeftButton]) { 
     insets = UIEdgeInsetsMake(0, 9.0f, 0, 0); 
    } 
    else { // IF ITS A RIGHT BUTTON 
     insets = UIEdgeInsetsMake(0, 0, 0, 9.0f); 
    } 
    return insets; 
} 


- (BOOL)isLeftButton { 
    return self.frame.origin.x < (self.superview.frame.size.width/2); 
} 

这个伟大的工程,但是当我弹出创建一个从导航控制器返回到这个主视图的视图控制器,该按钮仍然错误地放置了大约.3秒,然后它卡入正确的插入。

这是一个巨大的眼睛,我不知道如何阻止它像这样捕捉。有什么想法吗?谢谢!

我有像你一样的问题和其他许多问题。经过很长时间的努力修复,最终我做到了。这是您必须在* -Prefix.pch文件中包含的类别。就这样!

UINavigationItem + iOS7Spacing.h

#import <Foundation/Foundation.h> 
@interface UINavigationItem (iOS7Spacing) 
@end 

UINavigationItem + iOS7Spacing.m

#import "UINavigationItem+iOS7Spacing.h" 
#import <objc/runtime.h> 

@implementation UINavigationItem (iOS7Spacing) 

- (BOOL)isIOS7 
{ 
    return ([[[UIDevice currentDevice] systemVersion] compare:@"7" options:NSNumericSearch] != NSOrderedAscending); 
} 

- (UIBarButtonItem *)spacer 
{ 
    UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; 
    space.width = -11; 
    return space; 
} 

- (void)mk_setLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem 
{ 
    if ([self isIOS7] && leftBarButtonItem) { 
     [self mk_setLeftBarButtonItem:nil]; 
     [self mk_setLeftBarButtonItems:@[[self spacer], leftBarButtonItem]]; 
    } else { 
     [self mk_setLeftBarButtonItem:leftBarButtonItem]; 
    } 
} 

- (void)mk_setLeftBarButtonItems:(NSArray *)leftBarButtonItems 
{ 
    if ([self isIOS7] && leftBarButtonItems && leftBarButtonItems.count > 0) { 

     NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity:leftBarButtonItems.count + 1]; 
     [items addObject:[self spacer]]; 
     [items addObjectsFromArray:leftBarButtonItems]; 

     [self mk_setLeftBarButtonItems:items]; 
    } else { 
     [self mk_setLeftBarButtonItems:leftBarButtonItems]; 
    } 
} 

- (void)mk_setRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem 
{ 
    if ([self isIOS7] && rightBarButtonItem) { 
     [self mk_setRightBarButtonItem:nil]; 
     [self mk_setRightBarButtonItems:@[[self spacer], rightBarButtonItem]]; 
    } else { 
     [self mk_setRightBarButtonItem:rightBarButtonItem]; 
    } 
} 

- (void)mk_setRightBarButtonItems:(NSArray *)rightBarButtonItems 
{ 
    if ([self isIOS7] && rightBarButtonItems && rightBarButtonItems.count > 0) { 

     NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity:rightBarButtonItems.count + 1]; 
     [items addObject:[self spacer]]; 
     [items addObjectsFromArray:rightBarButtonItems]; 

     [self mk_setRightBarButtonItems:items]; 
    } else { 
     [self mk_setRightBarButtonItems:rightBarButtonItems]; 
    } 
} 

+ (void)mk_swizzle:(SEL)aSelector 
{ 
    SEL bSelector = NSSelectorFromString([NSString stringWithFormat:@"mk_%@", NSStringFromSelector(aSelector)]); 

    Method m1 = class_getInstanceMethod(self, aSelector); 
    Method m2 = class_getInstanceMethod(self, bSelector); 

    method_exchangeImplementations(m1, m2); 
} 

+ (void)load 
{ 
    [self mk_swizzle:@selector(setLeftBarButtonItem:)]; 
    [self mk_swizzle:@selector(setLeftBarButtonItems:)]; 
    [self mk_swizzle:@selector(setRightBarButtonItem:)]; 
    [self mk_swizzle:@selector(setRightBarButtonItems:)]; 
} 

@end 

UINavigationItem+iOS7Spacing category on GitHub

+0

我觉得这是最好的解决方案,比改变UIEdegeInset好,这个没有tap区域问题 – Nick

+0

非常好!这也解决了我的问题! – rockstarberlin

+0

完美的解决方案。如果我能,我会upvote它10次。 – kufi

不从马吕斯的答案子类UIButton或方法混写一个巨大的风扇:https://stackoverflow.com/a/19317105/287403

我只是使用了一个简单的包装,并将按钮的框架的x向负方向移动,直到找到正确的位置。按钮敲击似乎也很好(尽管如果需要,可以扩展按钮的宽度以匹配负偏移量)。

下面是我用它来生成一个新的后退按钮的代码:

- (UIBarButtonItem *) newBackButton { 
    // a macro for the weak strong dance 
    @weakify(self); 
    UIButton *backButton = [[UIButton alloc] init]; 
    [backButton setTitle:@"Back" forState:UIControlStateNormal]; 
    backButton.titleLabel.font = [UIFont systemFontOfSize:17]; 
    CGFloat width = [@"Back" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:17]} context:nil].size.width + 27; 
    backButton.frame = CGRectMake(-17.5, 0, width + 17.5, 44); 
    [backButton setImage:[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"] forState:UIControlStateNormal]; 
    [backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 14, 0, 0)]; 
    [backButton setTitleColor:mTCOrangeColor forState:UIControlStateNormal]; 
    backButton.contentEdgeInsets = UIEdgeInsetsZero; 
    backButton.imageEdgeInsets = UIEdgeInsetsZero; 
    [backButton addEventHandler:^(id sender) { 
     // a macro for the weak strong dance 
     @strongify(self); 
     // do stuff here 
    } forControlEvents:UIControlEventTouchUpInside]; 
    UIView *buttonWrapper = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 44)]; 
    [buttonWrapper addSubview:backButton]; 
    return [[UIBarButtonItem alloc] initWithCustomView:buttonWrapper]; 
} 
+0

这是我唯一的解决方案,它将成为每个使用UIButton作为子视图(+1)的解决方案, – Yossi

我还没有尝试过多个navigationBarButton项目的代码,但它似乎是工作单按钮。我已经覆盖了UINavigationBar和它的layoutSubviews方法。

首先,在文件顶部定义一个用于水平偏移量的常量。修改是如你所愿:

static CGFloat const kNavBarButtonHorizontalOffset = 10; 

layoutSubviews:

- (void)layoutSubviews{ 

    [super layoutSubviews]; 

    //Do nothing on iOS6 
    if (![[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f){return;} 

    UINavigationItem * navigationItem = [self topItem]; 

    for(UIBarButtonItem * item in [navigationItem rightBarButtonItems]){ 

     UIView * subview = [item customView]; 
     CGFloat width = CGRectGetWidth(subview.frame); 

     CGRect newRightButtonRect = CGRectMake(CGRectGetWidth(self.frame) - width - kNavBarButtonHorizontalOffset, 
              CGRectGetMinY(subview.frame), 
              width, 
              CGRectGetHeight(subview.frame)); 
     [subview setFrame:newRightButtonRect]; 

    } 

    for(UIBarButtonItem * item in [navigationItem leftBarButtonItems]){ 
     UIView * subview = [item customView]; 
     CGRect newRightButtonRect = CGRectMake(kNavBarButtonHorizontalOffset, 
              CGRectGetMinY(subview.frame), 
              CGRectGetWidth(subview.frame), 
              CGRectGetHeight(subview.frame)); 

     [subview setFrame:newRightButtonRect]; 
    } 
} 

或者,你可以调整你的自定义视图(-5左子视图,+5内容的帧为右子视图),并且只要您的自定义视图没有clipsToBounds设置为YES那么这些将被兑现。这不是最干净的,但其他建议的解决方案可能更加黑客IMO。

子视图将在IB中显示5点截止,但在模拟器中运行应用程序时会显示整个内容。