UIBarButtonItem with custom image and no border
Asked Answered
K

9

89

I want to create a UIBarButtonItem with a custom image, but I don't want the border that iPhone adds, as my Image has a special border.

It's the same as the back button but a forward button.

This App is for an inHouse project, so I don't care if Apple reject or approves it or likes it :-)

If I use the initWithCustomView:v property of the UIBarButtonItem, I can do it:

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

This works, but if I have to repeat this process in 10 views, this is not DRY.

I suppose I have to subclass, but what ?

  • NSView ?
  • UIBarButtonItem ?

thanks,

regards,

Krystinakrystle answered 21/4, 2010 at 8:27 Comment(2)
Thanks for sharing your code, that's all I needed :) .Pogonia
Everyone, I used the answer provided by San on Feb 6. It took all of 5 minutes to integrate into my Storyboard, and it worked perfectly. The Selector property is under Connections Inspector of IB. Control drag from UIButton to the ViewController object and the methods will pop up. Tap the method you want and you pretty much done. The only thing left would be some code cleanup. Used btnXXXXX.hidden to hide and unhide to replace barbuttonitem = nil. But this method was easy and very clean.Carma
G
44

You can add a method to UIBarButtonItem without subclassing it using custom category:

@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

So anywhere in your code you can create bar item calling this method (provided that you include a header with its declaration).

P.S. You do not need to use 'v' UIView as you can create UIBarButtonItem with a button as custom view directly.
P.P.S. You also need [forward release] in your code.

Goodnight answered 21/4, 2010 at 8:47 Comment(4)
The custom category: I have to create the header file with those declarations, and the implementation file, where I put the code you're refering ? thanksKrystinakrystle
Its work thanx alot but i am not able to write selector i dont want to write selector on category how can i write it on my classProbabilism
@NileshTupe what do you mean? You pass selector method and target - so target can be whatever object you wantGoodnight
BTW- I added this to my little open source repo for UIKit convenience categories. Thanks @Goodnight for the inspiration. (note all my stuff is ARC-based) github.com/egold/UIKitConvenience/blob/master/UIKitConvenience/…Hothouse
I
50

Another simple solution is

  1. Drag a standard UIButton
  2. Set the button's style to custom and set your image for that button
  3. Drag it onto the UINavigationBar
  4. Set Selector
Idocrase answered 6/2, 2012 at 6:30 Comment(2)
Brilliant! The only quirk - it would not work if you drag button straight to nav bar. Button has to be set to custom before it added to nav bar. Not sure why, but this is how it is. So step #1 - means drag UIBatton somewhere on you UI other than nav bar.Riyal
it is hard to be simple and effective. Nice answerVulvitis
G
44

You can add a method to UIBarButtonItem without subclassing it using custom category:

@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

So anywhere in your code you can create bar item calling this method (provided that you include a header with its declaration).

P.S. You do not need to use 'v' UIView as you can create UIBarButtonItem with a button as custom view directly.
P.P.S. You also need [forward release] in your code.

Goodnight answered 21/4, 2010 at 8:47 Comment(4)
The custom category: I have to create the header file with those declarations, and the implementation file, where I put the code you're refering ? thanksKrystinakrystle
Its work thanx alot but i am not able to write selector i dont want to write selector on category how can i write it on my classProbabilism
@NileshTupe what do you mean? You pass selector method and target - so target can be whatever object you wantGoodnight
BTW- I added this to my little open source repo for UIKit convenience categories. Thanks @Goodnight for the inspiration. (note all my stuff is ARC-based) github.com/egold/UIKitConvenience/blob/master/UIKitConvenience/…Hothouse
A
38

I found it this ways easy. It is sugested on top. "random.png" has to be in project. Just drag and drop any image.

 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;
Alienism answered 23/12, 2011 at 1:18 Comment(0)
O
6

An alternative is to subclass UIBarButtonItem. Why? So that the action is invoked on the target with the correct sender. In the code above, the sender argument in the action message is the UIButton instance, not the UIBarButtonItem instance. This would be important, for example, if you wish to present a UIPopoverController from the bar button item. By subclassing UIBarButtonItem, you can add an ivar that retains the original target, allowing our subclass instances to intercept, modify, and forward the action message with the proper sender.

So, CCFBarButtonItem.h:

#import <uIKit/UIBarButtonItem.h>

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

and 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
Observe answered 30/4, 2011 at 11:33 Comment(0)
N
5
UIBarButtonItem *menuItem = [[UIBarButtonItem alloc] initWithImage: [UIImage imageNamed:@"icon-menu.png"]
                                                                    style:UIBarButtonItemStylePlain
                                                                   target:self
                                                                   action:@selector(showMenu)];
Namedropping answered 2/4, 2014 at 16:54 Comment(0)
Q
3

This can also be done programmatically as well (of-course):

First, create a custom view. This custom view can contain an image, button or whatever else you would like. The custom view can be made programmatically or in 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];

Next, create a UIBarButtonItem and initialize it with the custom view.

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

Now, just add the custom UIBarButton to the leftBarButtonItem:

self.navigationItem.leftBarButtonItem = customBarButtonItem;
Quote answered 9/4, 2013 at 19:55 Comment(0)
S
1

Ok that category works very good because there are no problems with 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
Seagrave answered 29/11, 2012 at 12:56 Comment(0)
B
1

One another solution, think it's simpler in case when creating button programatically:

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];
Bohunk answered 19/7, 2013 at 13:46 Comment(0)
T
1

Check this out simple solution.

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

Here 1x1.png is a 1 pixel transparent png image which you can download from the link below

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

Theatrics answered 8/8, 2013 at 7:50 Comment(1)
You could just use [UIImage new] instead of using the transparent image.Earley

© 2022 - 2024 — McMap. All rights reserved.