2013-10-07 11 views
17

Quindi sto riscontrando lo stesso problema che molti altri stanno riscontrando durante la creazione di un UIBarButtonItem con un UIButton come visualizzazione personalizzata.Allineamento personalizzato UIBarButtonItem con iOS7

Fondamentalmente il pulsante è di circa 10 pixel verso sinistra o verso destra. Quando utilizzo un oggetto BarButtonItem normale senza una visualizzazione personalizzata, ciò non accade.

Questo post ha fornito una soluzione parziale: UIBarButton With Custom View

Ecco il mio codice ho creato da sottoclasse UIButton (come detto in altri post)

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

Questa grande opera, ma quando ho pop un controller di visualizzazione dal controller di navigazione di nuovo a questa vista principale, il pulsante è ancora posizionato in modo errato per circa 3 secondi, e quindi si inserisce nell'inserto corretto.

Questo è un pugno nell'occhio ENORME e non ho idea di come smettere di spezzare in questo modo. qualche idea? Grazie!

risposta

53

Ho avuto lo stesso problema come te e molti altri. Dopo tanto tempo ho provato a risolverlo, finalmente l'ho fatto. Questa è la categoria che devi includere nel tuo file * -Prefix.pch. E questo è tutto!

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

Penso che questa sia la soluzione migliore, meglio di cambiare UIEdegeInset, questo non ha problemi di area di tocco – Nick

+0

Molto buono! Questo ha risolto anche il mio problema! – rockstarberlin

+0

Soluzione perfetta. Se potessi, lo revocherei per 10 volte. – kufi

4

Non è un grande fan di sottoclassi UIButton o di un metodo swizzling dalla risposta di Marius: https://stackoverflow.com/a/19317105/287403

Ho appena usato un semplice wrapper e ho spostato la x della cornice del pulsante in una direzione negativa finché non ho trovato il posizionamento corretto. Anche il tocco dei pulsanti sembra andare bene (anche se è possibile estendere la larghezza del pulsante per far corrispondere l'offset negativo se necessario).

Ecco il codice che uso per generare un nuovo pulsante indietro:

- (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

Questa è l'unica soluzione che ha funzionato per me e sarà la soluzione per ognuno che usa UIButton come sottoview (+1) – Yossi

0

Non ho provato questo codice per gli oggetti multipli navigationBarButton, ma sembra di essere al lavoro per i singoli pulsanti. Ho annullato UINavigationBar e il suo metodo layoutSubviews.

In primo luogo, una costante per l'offset orizzontale è definita nella parte superiore del file. Modificare è come si desidera:

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

In alternativa, è possibile regolare le cornici dei contenuti della visualizzazione personalizzata (-5 per i subviews sinistra, +5 per i giusti subviews) e fino a quando la visualizzazione personalizzata non ha clipsToBounds impostato su YES, questi verranno onorati. Non è il più pulito, ma altre soluzioni suggerite possono essere ancora più hacky IMO.

Le visualizzazioni secondarie appariranno tagliate di 5 punti in IB, ma l'intero contenuto viene mostrato quando si esegue l'applicazione nel simulatore.

Problemi correlati