目标操作不工作?

我有一个自定义视图内的一个 UIBarButtonItem,设置通过调用 -initWithCustomView。 我的条形按钮项呈现得很好,但是当我点击它时,它不会调用目标对象上的操作。

这是我的密码:

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"someImage.png"]];
UIBarButtonItem *bbItem = [[UIBarButtonItem alloc] initWithCustomView:imageView];
self.navigationItem.leftBarButtonItem = bbItem;
[imageView release];
[bbItem setTarget:self];
[bbItem setAction:@selector(deselectAll)];
58129 次浏览

Jacob, everything looks good, however you may not have provided the correct selector.

Can you verify that your action is actually declared

- (void) deselectAll;

and not

- (void) deselectAll:(id)sender;

If it's the latter, you will need to set the action to @selector(deselectAll:). (note the semi-colon to match the method declaration)

Also, void might be IBAction, but that's not relevant to this problem you're having.

Is your custom view eating touch events or passing them on to parent view?

I do not think the target and action of the UIBarButtonItem apply to custom views. Try using a UIButton instead of UIImageView and applying the target and action to the button.

Sample code in Swift:

let button  = UIButton(type: .Custom)
if let image = UIImage(named:"icon-menu.png") {
button.setImage(image, forState: .Normal)
}
button.frame = CGRectMake(0.0, 0.0, 30.0, 30.0)
button.addTarget(self, action: #selector(MyClass.myMethod), forControlEvents: .TouchUpInside)
let barButton = UIBarButtonItem(customView: button)
navigationItem.leftBarButtonItem = barButton

Here is how I make it work:

UIButton* infoButton = [UIButton buttonWithType: UIButtonTypeInfoLight];
[infoButton addTarget:self action:@selector(displayAboutUs) forControlEvents:UIControlEventTouchDown];


UIBarButtonItem* itemAboutUs =[[UIBarButtonItem alloc]initWithCustomView:infoButton];
…

I had a similar problem. And I initially followed the path suggested by @drawnonward, but then ran into trouble when I tried to have my action present a popover controller on an iPad: Using an embedded UIButton as a custom view means the UIButton is the sender of the event, and the popover controller’s presentPopoverFromBarButtonItem: method crashes when it tries to send it messages which are only appropriate to actual UIBarButtonItems.

The solution I eventually found was to steal the image I wanted to use (the “info” icon) from a throwaway UIButton, and construct my UIBarButtonItem as follows:

// Make the info button use the standard icon and hook it up to work
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
UIBarButtonItem *barButton = [[[UIBarButtonItem alloc]
initWithImage:infoButton.currentImage
style:UIBarButtonItemStyleBordered
target:self
action:@selector(showInfo:)] autorelease];

Using this initializer yields a bar button whose target and selector actually work. It is also easier than wrapping the image in a custom view, but that is just icing.

To make this easy to work with, I created a category on UIBarButtonItem which looks like this:

@implementation UIBarButtonItem (CustomButtonView)


- (void)setButtonImage:(UIImage *)image
{
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:image forState:UIControlStateNormal];
[button sizeToFit];
[button addTarget:self.target action:self.action forControlEvents:UIControlEventTouchUpInside];
self.customView = button;
}


- (UIImage *)buttonImage
{
return [(UIButton *)self.customView imageForState:UIControlStateNormal];
}


@end

In your client code, simply use:

myBarButtonItem.buttonImage = [UIImage imagedNamed:@"image_name"];

Done this way you can still hook up your targets and actions in IB (pushing as much UI config into IB as you can is a Good Thing).

Here's how I implemented the UIButton inside of the UIBarButtonItem:

UIButton *logoButton = [UIButton buttonWithType:UIButtonTypeCustom];
[logoButton setImage: [UIImage imageNamed:@"icon.png"] forState:UIControlStateNormal];
logoButton.frame = CGRectMake(0, 0, 30, 30);
[logoButton addTarget:self action:@selector(showAbout:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:logoButton];
self.navigationItem.rightBarButtonItem = barItem;
[barItem release];

I had the same problem, but was averse to using a UIButton instead of a custom view for my UIBarButtonItem (per drawnonward's response).

Alternatively, you could add a UIGestureRecognizer to the custom view before using it to initialize UIBarButtonItem; this appears to work in my project.

This is how I would modify your original code:

UIImageView *SOCImageView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:@"cancel_wide.png"]];


UITapGestureRecognizer *tapGesture =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(deselectAll:)];
[SOCImageView addGestureRecognizer:tapGesture];


SOItem.leftBarButtonItem =
[[[UIBarButtonItem alloc] initWithCustomView:SOCImageView] autorelease];
[tapGesture release];
[SOCImageView release];

Swift 3. I had a similar issue where I had a custom view inside of the bar button item. In order to get the tap to work I assigned a gesture to the view and set the action. The view needed to be an outlet to assign to it. Doing this it worked with the custom view.

Setting the gesture as class variable

@IBOutlet weak var incidentView: UIView!
let incidentTap = UITapGestureRecognizer()

In viewDidLoad

incidentTap.addTarget(self, action: #selector(self.changeIncidentBarItem))
incidentView.addGestureRecognizer(incidentTap)

If you do not want to settle with an UIImage and have a custom view in your barbuttonitem, set a tap gesture recognizer to your barbuttonitem's customview property

let tap = UITapGestureRecognizer(target: self, action: #selector(goProButtonPressed)) deviceStatusBarButtonItem.customView?.addGestureRecognizer(tap)

Swift 3 : Below is my full implementation for button customization and event handling.

override func viewDidLoad() {
super.viewDidLoad()


let button = UIButton.init(type: .custom)
button.setTitle("Tester", for: .normal)
button.setTitleColor(.darkGray, for: .normal)
button.layer.borderWidth = 1
button.layer.cornerRadius = 5
button.layer.borderColor = UIColor.darkGray.cgColor
button.addTarget(self, action: #selector(self.handleButton), for: .touchUpInside)


self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
}


override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)


if let button = self.navigationItem.rightBarButtonItem?.customView {
button.frame = CGRect(x:0, y:0, width:80, height:34)
}
}


func handleButton( sender : UIButton ) {
// It would be nice is isEnabled worked...
sender.alpha = sender.alpha == 1.0 ? 0.5 : 1.0
}

Hope this helps