带有自定义图像且无边框的 UIBarButtonItem

我想创建一个带有自定义图像的 UIBarButtonItem,但是我不想要 iPhone 添加的边框,因为我的 Image 有一个特殊的边框。

它和后退按钮一样,但是是前进按钮。

这个应用程序是一个 inHouse 项目,所以我不在乎苹果是否拒绝或批准或喜欢它: -)

如果我使用 UIBarButtonItem 的 initWithCustomView: v 属性,我可以这样做:

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

这是可行的,但是如果我必须在10个视图中重复这个过程,这就不是 DRY。

我想我必须继承类,但是什么呢?

  • NSView?
  • UIBarButtonItem? ?

谢谢,

问候,

67617 次浏览

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.

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

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;

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

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

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;

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

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

UIBarButtonItem *menuItem = [[UIBarButtonItem alloc] initWithImage: [UIImage imageNamed:@"icon-menu.png"]
style:UIBarButtonItemStylePlain
target:self
action:@selector(showMenu)];