Set action for custom UIBarButtonItem - ios

I've created a UIView that has to be added to BarButtonItem. I can't set action to this button though. Here's the code I am using:
self.menuBarButton = [[UIBarButtonItem alloc] initWithCustomView:self.containerView];
[self.menuBarButton setTarget:self];
[self.menuBarButton setAction:#selector(menuButtonTapped)];
self.navigationItem.leftBarButtonItem = self.menuBarButton;
The action doesn't run with success. I also tried to set an action directly to bar button after it's set to custom.
[self.navigationItem.leftBarButtonItem setTarget:self];
[self.navigationItem.leftBarButtonItem setAction:#selector(menuButtonTapped)];
When I do it for the usual barbutton item it works. Could you help spotting what's wrong?

A UIBarButtonItem initialized with a custom view expects the view to handle user interaction:
The bar button item created by this method does not call the action method of its target in response to user interactions. Instead, the bar button item expects the specified custom view to handle any user interactions and provide an appropriate response.
If your UIView doesn't handle any user interaction yet, then as Miken says, you can replace the UIView with a UIButton that you've configured with addTarget:selector.
In particular, if you're trying to set an image, UIButton can do that via setImage:forState:.
See also this answer.

When you use a custom view for a UIBarButtonItem, then you have to handle the actions yourself. Replace your custom view with a UIButton, or add a UIButton to your custom view, and then add a target & selector to the button.
Here's an example but keep in mind I'm free-forming this example, so it may not be 100% accurate code but the concept will be the same.
UIButton *button = [UIButton buttonWithType:UIBarButtonTypeCustom];
UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithCustomView:button];
[button addTarget:self selector:#selector(myBtnClk)];

To add action to a button you need two things: create a method, then add it to the button. Here is the method (pay attention to the syntax) :
- (IBAction) my_method : (id) sender {
UIButton * btn = sender;
}
Now the action assignment (where the button was created) :
[ my_button addTarget : self
action : #selector( my_method : )
forControlEvents : UIControlEventTouchUpInside ];

Instead of using - setAction alone, I recommend using: - addTarget:action:forControlEvents:. In iOS (AppKit) there are many type of events. You can take a look at the attached image for reference. Typically Touch up inside is appropriate for button press down.

I decided this problem. All answers was about adding target and action to UIButton and then create a UIBarButtonItem with this button. But as I said it's really necessary to set UIView to this button(I've forgotten to say it's necessary because this UIView has animation, maybe that's why all answers was good but wrong for my situation.)
But one answer(https://stackoverflow.com/a/28054357/4464891) from Jason Owen gives me great idea. I have to use my custom view, so I've set selector to my custom UIView by adding UITapGestureRecognizer with initWithTarget:action::
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(menuButtonTapped)];
[self.containerView addGestureRecognizer:tapRecognizer];
And when I click button tapRecognizer runs my selector. So that's it. Hope it'll be helpful for someone=)

Related

iOS: possible to superimpose barbuttonitem on other barbuttonitem and swap them

I have a screen that displays some info in a textview and I would like the user to be able to edit it.
Right now, I have an edit button on the right side of the navigation bar that I create in code as follows:
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStylePlain target:self action:#selector(gotoEdit)];
self.navigationItem.rightBarButtonItem = editButton;
For editing, I could launch a new view controller but it would be cleaner, I think, to just use the textview.editable property to make the text view editable.
However, I would then need to change the title and function of the uibarbuttonitem from edit to save.
You apparently cannot change the title of a system edit button and I'd just as soon not create a custom bar button item although this may ultimately prove necessary.
It is possible to hide bar button items by making their color clear and disabling interaction. Therefore, I had the idea of putting two in the same place and hiding and showing them accordingly.
Hence my question. Is it possible to put two in the same place?
Thanks for any ideas on this.
If you are using storyboards...you can drag and drop a UIButton to the rightBarButtonItem. Make this button a property and set the initial title to "Edit".
In the Action:
- (IBAction) editButton (id){
if(!isEditing){
// Prep for editing
[self.editButton setTitle:"Save" forState:UIControlStateNormal];
isEditing = true;
}else{
// Prep for save
[self.editButton setTitle:"Edit" forState:UIControlStateNormal];
isEditing = false;
}
}

When tapping a UIButton that was created programmatically is it possible to push to a controller that is editable in interface builder?

Created a UIButton programmatically but the page it needs to link to will need to be the root controller view of a UINavigationController.
This page would be easier to create in interface builder rather than in code. When the button in question is tapped it needs to segue to another controller/view that I can edit in interface builder.
Possible or impossible?
If possible how can I do this? I feel I'll run into this problem quite often.
You can do this :
Button creation:
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[btn addTarget:self action:#selector(btnMethod:) forControlEvents:UIControlEventTouchUpInside];
Button method:
- (void)btnMethod:(UIButton *)sender
{
[self performSegueWithIdentifier:#"MySegueIdentifier" sender:sender];
}
Sure it's possible:
Create the button:
UIButton *bottonOne = [[UIButton alloc]initWithFrame:CGRectMake(10, 15, 65, 12)];
The set it up with a title / image as you need. Once you have done that do this:
[buttonOne addTarget:self action:#selector(buttonOnepressed) forControlEvents:UIControlEventTouchUpInside];
Then in the same class create a method called buttonOnepressed
-(void)buttonOnePressed
{
//preform the steps needed for your segue method and anything else you want to do when the button has been tapped
}
Edit
After reading your comments - you want a button you've created in code, to perform a segue without manually invoking the segue (Writing code to actually show the new screen) and you want it to behave like it would if you did a drag and drop in IB. If that's the case - the short answer is simply, no. If you create a button in code, all its actions need to be done in code, too.
Edit 2
Try this:
In IB create a "generic" segue like this:
Ctrl-drag from the source view controller to the other view you want to do to when the button is tapped. You can use the view controller object at the bottom of the scene to do this.
Give the segue an identifier.
Then use [self performSegueWithIdentifier#"Your Identifier"]; in your button tapped method to perform the segue

How to perform performSegueWithIdentfier from within UIView

Ok so I have a UIButton embedded into a UIImageView which forms part of a UIView.
The button's selector calls a method which should run:
[self performSegueWithIdentifier:#"SegueToMoreInfo"];
However I get the error:
no visible at interface for 'myclassname' declares the selector 'performSegueWithIdentifier'.
Basically I really need to perform a segue from within the UIView. If not possible how would I call from the UIViewController instead?
EDIT: MORE INFO:
//adding button
UIButton *attractionButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[attractionButton addTarget:self
action:#selector(buttonClicked:)
forControlEvents:UIControlEventTouchUpInside];
[attractionButton setTitle:#"Attraction Info" forState:UIControlStateNormal];
attractionButton.frame = CGRectMake(80.0, 80, 160.0, 40.0);
[_image1 addSubview:attractionButton];
My method :
(IBAction)buttonClicked:(id)sender
{
[self performSegueWithIdentifier:#"SegueToMoreInfo" sender:sender];
}
[self performSegueWithIdentifier:#"aseguename" sender:self];
is a UIViewController method. That is why you are getting this error. Also views should not talk to ViewControllers except through protocols.
Having said that, you are going about this the wrong way. IBActions for buttons and other UIView objects should be in the ViewController. So I would move the IBAction to your View Controller and hook it to the button from there. Then insert your code in that IBAction.
Update after the code posted:
All of the code posted should be in your View Controller. I would just change:
[_image1 addSubview:attractionButton];
to
[self.view addSubview:attractionButton];
or if you really want that button to be a subview to your image, then you can leave your code, just make sure to create an IBOutlet property for that image, from your image in interface builder to your View Controller and call it _image1.
Hope this helps

Why [UIBarButtonItem setCustomView:] method disable segue in Storyboard?

I have Storyboard in my project. I use [UIBarButtonItem setCustomView:] method to customize toolbar buttons. For example:
[self setCustomView:[[UIImageView alloc] initWithImage:image]];
Now they looks as I need. But I found that this method somehow disables segue that I set for this toolbar item. I mean, segue works without it, but when I tried to use this method for customization segue don't work. But why?
I don't want to use target-action pattern from code, I believe it is possible to use only Storyboard.
I've been trying to configure all of the segues in the storyboard as well but I needed to create a custom view for the rightBarButtonItem. To make sure the segue still works, just add this line before setting the customView:
[filterButton addTarget:self.navigationItem.rightBarButtonItem.target action:self.navigationItem.rightBarButtonItem.action forControlEvents:UIControlEventTouchUpInside];
This way the segues you set up in your storyboard will still fire with customViews.
My entire custom button code looks like this:
UIButton *filterButton = [UIButton buttonWithType:UIButtonTypeCustom];
[filterButton setImage:[UIImage imageNamed:#"filter"] forState:UIControlStateNormal];
[filterButton setFrame:CGRectMake(0, 0, 36, 36)];
[filterButton addTarget:self.navigationItem.rightBarButtonItem.target action:self.navigationItem.rightBarButtonItem.action forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.rightBarButtonItem.customView = filterButton;
I've tried what you have done with the same result - the picture is correct but the UIBarButtonItem doesn't react when pressed. Possibly this is a bug. My work around is as follows:
To do this in storyboard add a UIButton to the tool bar. You should see that storyboard adds it by putting the UIButton inside of the UIBarButton. Add the segue on the UIButton. Customize the UIButton in storyboard. In my App I set the size to 40 x 40. Then in your code customize the UIButton with the view. Here is an example of the code to add the imageView to the UIButton:
[sampleImageView setFrame:CGRectMake(0, 0, 40, 40)];
[swapButton addSubview:sampleImageView];
Note: Storyboard can be quirky about adding UIButtons to toolbars. It seems as if you do it in a toolbar that is tied to a navigation controller it won't let you add it. I've worked around this by adding a dummy view controller to the storyboard, adding a toolbar to that, then dragging the UIButton into that toolbar. Storyboard will create that for you by encapsulating the UIButton in a UIButtonBarItem. You can then copy then over to the the desired toolbar in your project and delete dummy view controller.
There are other ways to do this such as creating the buttons in code and adding them to the toolbar. The method above minimizes code.

MFMailCompose Custom buttons

UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithCustomView:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cancel.png"]]];
button.target = picker.navigationBar.topItem.leftBarButtonItem ;
button.action = picker.navigationBar.topItem.leftBarButtonItem.action;
picker.navigationBar.topItem.leftBarButtonItem=button;
Hi folks, I'm trying to change the style of the buttons of the mail composer. The above code does change the look of the button, however the action seems to be lost. Any ideas how I can overcome this? Thanks.
The fix for this is fairly simple. You add a method to this button and then define what should happen in the method. So first, put this line after you declare your button.
[button addTarget:self action:#selector(aButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
That will add a method to be called when the button is clicked/touched. Then, later in the code, you create the actual method that the button will be calling.
-(void)aButtonClicked:(id)sendr{
//Do stuff here
}
Hope this helped :)

Resources