UIBarButtonItem con imagen personalizada y sin borde

89

Quiero crear un UIBarButtonItem con una imagen personalizada, pero no quiero el borde que agrega el iPhone, ya que mi imagen tiene un borde especial.

Es lo mismo que el botón de retroceso pero un botón de avance.

Esta aplicación es para un proyecto inHouse, así que no me importa si Apple la rechaza, la aprueba o le gusta :-)

Si utilizo la propiedad initWithCustomView: v de UIBarButtonItem, puedo hacerlo:

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];

Esto funciona, pero si tengo que repetir este proceso en 10 vistas, esto no es SECO.

Supongo que tengo que hacer una subclase, pero ¿qué?

  • NSView?
  • UIBarButtonItem?

Gracias,

Saludos,

mongeta
fuente
3
Gracias por compartir tu código, eso es todo lo que necesitaba :).
Max
1
Todos, utilicé la respuesta proporcionada por San el 6 de febrero. Me tomó 5 minutos integrarlo en mi Storyboard y funcionó perfectamente. La propiedad Selector se encuentra en Connections Inspector of IB. Controle el arrastre de UIButton al objeto ViewController y aparecerán los métodos. Toque el método que desee y ya está. Lo único que quedaba sería una limpieza de código. Se usó btnXXXXX.hidden para ocultar y mostrar para reemplazar barbuttonitem = nil. Pero este método fue fácil y muy limpio.
user589642

Respuestas:

44

Puede agregar un método a UIBarButtonItem sin subclasificarlo usando una categoría 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

Entonces, en cualquier lugar de su código, puede crear un elemento de barra que llame a este método (siempre que incluya un encabezado con su declaración).

PD: no es necesario utilizar 'v' UIView ya que puede crear UIBarButtonItemcon un botón como vista personalizada directamente.
PPS También necesita [versión avanzada] en su código.

Vladimir
fuente
La categoría personalizada: tengo que crear el archivo de encabezado con esas declaraciones y el archivo de implementación, ¿dónde pongo el código que estás refiriendo? gracias
mongeta
Su trabajo muchas gracias, pero no puedo escribir el selector, no quiero escribir el selector en la categoría, ¿cómo puedo escribirlo en mi clase?
Nilesh Tupe
@NileshTupe, ¿a qué te refieres? Pasas el método selector y el objetivo, por lo que el objetivo puede ser el objeto que quieras
Vladimir
2
Por cierto, agregué esto a mi pequeño repositorio de código abierto para las categorías de conveniencia de UIKit. Gracias @Vladimir por la inspiración. (tenga en cuenta que todas mis cosas están basadas en ARC) github.com/egold/UIKitConvenience/blob/master/UIKitConvenience/…
Eric Goldberg
50

Otra solución simple es

  1. Arrastre un UIButton estándar
  2. Configure el estilo del botón como personalizado y configure su imagen para ese botón
  3. Arrástrelo a UINavigationBar
  4. Establecer selector
san
fuente
1
Probablemente la solución más sencilla. ¡Gracias!
Prine
1
¡Brillante! La única peculiaridad: no funcionaría si arrastra el botón directamente a la barra de navegación. El botón debe configurarse como personalizado antes de agregarlo a la barra de navegación. No estoy seguro de por qué, pero así es como es. Entonces, el paso n. ° 1 significa arrastrar UIBatton en algún lugar de la interfaz de usuario que no sea la barra de navegación.
Andrei Tchijov
1
es difícil ser sencillo y eficaz. Buena respuesta
Add080bbA
37

Lo encontré así de fácil. Se sugiere en la parte superior. "random.png" tiene que estar en el proyecto. Simplemente arrastre y suelte cualquier imagen.

 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
fuente
6

Una alternativa es la subclase UIBarButtonItem. ¿Por qué? Para que la acción se invoque en el destino con el remitente correcto. En el código anterior, el argumento del remitente en el mensaje de acción es la instancia de UIButton, no la instancia de UIBarButtonItem. Esto sería importante, por ejemplo, si desea presentar un UIPopoverController desde el elemento del botón de la barra. Al subclasificar UIBarButtonItem, puede agregar un ivar que retiene el objetivo original, lo que permite que nuestras instancias de subclase intercepten, modifiquen y reenvíen el mensaje de acción con el remitente adecuado.

Entonces, CCFBarButtonItem.h:

#import <uIKit/UIBarButtonItem.h>

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

y 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
fuente
5
UIBarButtonItem *menuItem = [[UIBarButtonItem alloc] initWithImage: [UIImage imageNamed:@"icon-menu.png"]
                                                                    style:UIBarButtonItemStylePlain
                                                                   target:self
                                                                   action:@selector(showMenu)];
alexmorhun
fuente
3

Esto también se puede hacer mediante programación (por supuesto):

Primero, cree una vista personalizada. Esta vista personalizada puede contener una imagen, un botón o cualquier otra cosa que desee. La vista personalizada se puede crear mediante programación o en 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];

A continuación, cree un UIBarButtonItem e inicialícelo con la vista personalizada.

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

Ahora, simplemente agregue el UIBarButton personalizado al leftBarButtonItem:

self.navigationItem.leftBarButtonItem = customBarButtonItem;
abriggs
fuente
1

Ok, esa categoría funciona muy bien porque no hay problemas con 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
fuente
1

Mira esta sencilla solución.

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

Aquí 1x1.png es una imagen png transparente de 1 píxel que puede descargar desde el siguiente enlace

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

José Fremy
fuente
Puede usar [UIImage new] en lugar de usar la imagen transparente.
James Campbell
0

Otra solución, creo que es más simple en el caso de crear un botón programáticamente:

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
fuente