UIBarButtonItem com imagem personalizada e sem borda

89

Quero criar um UIBarButtonItem com uma imagem personalizada, mas não quero a borda que o iPhone adiciona, pois minha imagem tem uma borda especial.

É o mesmo que o botão Voltar, mas é um botão Avançar.

Este aplicativo é para um projeto interno, então não me importo se a Apple o rejeitar, aprovar ou gostar :-)

Se eu usar a propriedade initWithCustomView: v do UIBarButtonItem, posso fazer isso:

UIImage *image = [UIImage imageNamed:@"right.png"];

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage: [image stretchableImageWithLeftCapWidth:7.0 topCapHeight:0.0] forState:UIControlStateNormal];
[button setBackgroundImage: [[UIImage imageNamed: @"right_clicked.png"] stretchableImageWithLeftCapWidth:7.0 topCapHeight:0.0] forState:UIControlStateHighlighted];

 button.frame= CGRectMake(0.0, 0.0, image.size.width, image.size.height);

[button addTarget:self action:@selector(AcceptData)    forControlEvents:UIControlEventTouchUpInside];

UIView *v=[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, image.size.width, image.size.height) ];

[v addSubview:button];

UIBarButtonItem *forward = [[UIBarButtonItem alloc] initWithCustomView:v];

self.navigationItem.rightBarButtonItem= forward;

[v release];
[image release];

Isso funciona, mas se eu tiver que repetir esse processo em 10 visualizações, isso não é DRY.

Suponho que tenho que fazer uma subclasse, mas o quê?

  • NSView?
  • UIBarButtonItem?

obrigado,

Saudações,

Mongeta
fonte
3
Obrigado por compartilhar seu código, isso é tudo que eu precisava :).
Máx.
1
Pessoal, usei a resposta fornecida por San em 6 de fevereiro. Demorou 5 minutos para integrar meu Storyboard e funcionou perfeitamente. A propriedade Selector está em Connections Inspector of IB. Arraste o controle de UIButton para o objeto ViewController e os métodos irão aparecer. Toque no método desejado e pronto. A única coisa que restaria seria alguma limpeza de código. Usado btnXXXXX.hidden para ocultar e mostrar para substituir barbuttonitem = nil. Mas esse método era fácil e muito limpo.
user589642

Respostas:

44

Você pode adicionar um método a UIBarButtonItem sem subclassificá-lo usando a categoria personalizada:

@interface UIBarButtonItem(MyCategory)

+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image target:(id)target action:(SEL)action;

@end

@implementation UIBarButtonItem(MyCategory)

+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image target:(id)target action:(SEL)action{
 // Move your item creation code here
}
@end

Portanto, em qualquer lugar do seu código, você pode criar um item de barra chamando esse método (desde que inclua um cabeçalho com sua declaração).

PS Você não precisa usar 'v' UIView, pois pode criar UIBarButtonItemcom um botão como visualização personalizada diretamente.
PPS Você também precisa de [liberação direta] em seu código.

Vladimir
fonte
A categoria personalizada: tenho que criar o arquivo de cabeçalho com essas declarações, e o arquivo de implementação, onde coloco o código que você está se referindo? obrigado
mongeta,
Seu trabalho muito obrigado, mas eu não sou capaz de escrever seletor Eu não quero escrever seletor na categoria, como posso escrevê-lo na minha classe
Nilesh Tupe
@NileshTupe o que você quer dizer? Você passa o método do seletor e o alvo - então o alvo pode ser qualquer objeto que você quiser
Vladimir,
2
BTW- eu adicionei isso ao meu pequeno repositório de código aberto para categorias de conveniência UIKit. Obrigado @Vladimir pela inspiração. (observe que todas as minhas coisas são baseadas em ARC) github.com/egold/UIKitConvenience/blob/master/UIKitConvenience/…
Eric Goldberg
50

Outra solução simples é

  1. Arraste um UIButton padrão
  2. Defina o estilo do botão como personalizado e defina sua imagem para esse botão
  3. Arraste-o para o UINavigationBar
  4. Definir Seletor
san
fonte
Provavelmente a solução mais fácil. Obrigado!
Prine em
1
Brilhante! A única peculiaridade - não funcionaria se você arrastar o botão direto para a barra de navegação. O botão deve ser definido como personalizado antes de ser adicionado à barra de navegação. Não sei por que, mas é assim que funciona. Portanto, a etapa 1 - significa arrastar o UIBatton para algum lugar na interface do usuário que não seja a barra de navegação.
Andrei Tchijov
é difícil ser simples e eficaz. Boa resposta
Add080bbA
37

Eu achei isso fácil. É sugerido no topo. "random.png" deve estar no projeto. Basta arrastar e soltar qualquer imagem.

 UIButton *a1 = [UIButton buttonWithType:UIButtonTypeCustom];
        [a1 setFrame:CGRectMake(0.0f, 0.0f, 25.0f, 25.0f)];
        [a1 addTarget:self action:@selector(randomMsg) forControlEvents:UIControlEventTouchUpInside];
        [a1 setImage:[UIImage imageNamed:@"config.png"] forState:UIControlStateNormal];
        UIBarButtonItem *random = [[UIBarButtonItem alloc] initWithCustomView:a1];

 //? line incomplete ?//   imageNamed:@"random.png"] style:UIBarButtonItemStylePlain target:self action:@selector(randomMsg)];

    self.navigationItem.rightBarButtonItem = random;
m-farhan
fonte
6

Uma alternativa é a subclasse UIBarButtonItem. Por quê? Para que a ação seja invocada no destino com o remetente correto. No código acima, o argumento do remetente na mensagem de ação é a instância UIButton, não a instância UIBarButtonItem. Isso seria importante, por exemplo, se você deseja apresentar um UIPopoverController a partir do item do botão da barra. Subclassificando UIBarButtonItem, você pode adicionar um ivar que retém o destino original, permitindo que nossas instâncias de subclasse interceptem, modifiquem e encaminhem a mensagem de ação com o remetente adequado.

Então, CCFBarButtonItem.h:

#import <uIKit/UIBarButtonItem.h>

@interface CCFBarButtonItem : UIBarButtonItem
{
@protected
    id _originalTarget;
}
- (id)initWithImage:(UIImage *)image target:(id)target action:(SEL)action;
@end

e CCFBarButtonItem.m

#import "CCFBarButtonItem.h"
#import <UIKit/UIButton.h>
#import <UIKit/UIView.h>
#import <UIKit/UIImage.h>

@implementation CCFBarButtonItem

#pragma mark - Object life cycle

- (id)initWithImage:(UIImage *)image target:(id)target action:(SEL)action;
{
    _ASSIGN( _originalTarget, target );

    UIButton *imgButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [imgButton setImage:image forState:UIControlStateNormal];
    imgButton.frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
    [imgButton addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];

    self = [super initWithCustomView:imgButton];

    return self;
}

- (void)dealloc;
{
    MCRelease(_originalTarget);
    [super dealloc];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
{
    if( [_originalTarget respondsToSelector:aSelector] )
    {
        return [_originalTarget methodSignatureForSelector:aSelector];
    }
    else
    {
        return [super methodSignatureForSelector:aSelector];
    }
}

- (void)forwardInvocation:(NSInvocation *)anInvocation;
{
    SEL aSelector = [anInvocation selector];
    if( [_originalTarget respondsToSelector:aSelector] )
    {
        //  modify the 'sender' argument so that it points to self
        [anInvocation setArgument:&self atIndex:2];
        [anInvocation invokeWithTarget:_originalTarget];
    }
    else
    {
        [self doesNotRecognizeSelector:aSelector];
    }
}
@end
FluffulousChimp
fonte
5
UIBarButtonItem *menuItem = [[UIBarButtonItem alloc] initWithImage: [UIImage imageNamed:@"icon-menu.png"]
                                                                    style:UIBarButtonItemStylePlain
                                                                   target:self
                                                                   action:@selector(showMenu)];
alexmorhun
fonte
3

Isso também pode ser feito programaticamente (é claro):

Primeiro, crie uma visualização personalizada. Esta visualização personalizada pode conter uma imagem, botão ou qualquer outra coisa que você desejar. A visualização personalizada pode ser feita de forma programática ou em IB:

UIImage *customImage = [UIImage imageNamed:@"imageName"];
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, customImage.size.width, customImage.size.height)];
customView.backgroundColor = [UIColor colorWithPatternImage:customImage];

Em seguida, crie um UIBarButtonItem e inicialize-o com a visualização personalizada.

UIBarButtonItem *customBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customView];

Agora, basta adicionar o UIBarButton personalizado ao leftBarButtonItem:

self.navigationItem.leftBarButtonItem = customBarButtonItem;
Abriggs
fonte
1

Ok, essa categoria funciona muito bem porque não há problemas com o Popovercontroller :-)

#import <UIKit/UIKit.h>

@interface UIBarButtonItem (BarButtonItemExtended)
+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image target:(id)target action:(SEL)action;
-(void)performBarButtonAction:(id)sender;
@end



#import "UIBarButtonItem+BarButtonItemExtended.h"

@implementation UIBarButtonItem (BarButtonItemExtended)

+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image target:(id)target action:(SEL)action
{    
    UIButton *imgButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [imgButton setImage:image forState:UIControlStateNormal];
    imgButton.frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);

    UIBarButtonItem *b = [[UIBarButtonItem alloc]initWithCustomView:imgButton];

    [imgButton addTarget:b action:@selector(performBarButtonAction:) forControlEvents:UIControlEventTouchUpInside];

    [b setAction:action];
    [b setTarget:target];

    return b;
}

-(void)performBarButtonAction:(UIButton*)sender
{
    [[self target] performSelector:self.action withObject:self];
}
@end
Raegtime
fonte
1

Confira esta solução simples.

- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
barButtonItem.image = [UIImage imageNamed:@"navButton.png"];
barButtonItem.style = UIBarButtonItemStylePlain;

[barButtonItem setBackgroundImage:[UIImage imageNamed:@"1x1.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
self.masterPopoverController = popoverController;
}

Aqui, 1x1.png é uma imagem png transparente de 1 pixel que você pode baixar no link abaixo

http://commons.wikimedia.org/wiki/File:1x1.png

Fremy Jose
fonte
Você pode apenas usar [UIImage new] em vez de usar a imagem transparente.
James Campbell
0

Uma outra solução, acho que é mais simples no caso de criar um botão de forma programática:

UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithImage:defaultImage
                                             landscapeImagePhone:landscapeImage
                                                           style:UIBarButtonItemStylePlain
                                                          target:self
                                                          action:@selector(someSelector)];
[button setBackgroundImage:[UIImage new] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[button setBackgroundImage:[UIImage new] forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
Mikhail
fonte