2013-10-07 2 views
17

Так что у меня такая же проблема, что и многие другие возникают при создании UIBarButtonItem с UIButton как пользовательский вид.Пользовательский 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); 
} 

Это прекрасно работает, но когда я сую контроллер просмотра от навигационного контроллера обратно к этому главному виду, кнопка по-прежнему неправильно расположена примерно на 0,3 секунды, а затем она привязывается к правильной вставке.

Это ОГРОМНОЕ бельмо на глазу, и я не знаю, как остановить его от щелчка. Есть предположения? Благодаря!

ответ

53

У меня была такая же проблема, как вы и многие другие. После долгого времени, пытаясь исправить это, я наконец-то это сделал. Это категория, которую вы должны включить в свой файл * -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, это не имеет проблемы с зоной. – Nick

+0

Очень хорошо! Это тоже решило мою проблему! – rockstarberlin

+0

Идеальное решение. Если бы я мог, я бы его повысил 10 раз. – kufi

4

Не огромный поклонник подклассов UIButton или метод swizzling от ответа Мариуса в: 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 как subview (+1) – Yossi

0

Я не пробовал этот код для нескольких элементов 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]; 
    } 
} 
0

Кроме того, вы можете настроить кадры содержимого вашего пользовательского вида (-5 для левого подвидов, +5 за право подобозрения), и пока ваш пользовательский вид не имеет clipsToBounds, установленного на YES, тогда они будут выполнены. Это не самый чистый, но другие предлагаемые решения могут быть еще более хакерскими ИМО.

Подвижные объекты будут отображаться на 5 пунктов в IB, но все содержимое отображается при запуске приложения в симуляторе.

Смежные вопросы