Issues with UINavigationItem changing properties at runtime - ios

i have a Navigation Bar, wich contains a Navigation Item, which contains 2 Bar Buttons, these are created in the Storyboard, and i wanted to change 1 of the buttons at runtime, now this works:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UINavigationItem *thisNavBar = [self myNavigationItem];
thisNavBar.rightBarButtonItem = nil; // this works, it gets removed
UIBarButtonItem *insertBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(insertSkemaItem:)];
thisNavBar.rightBarButtonItem = insertBtn; // this also works, it sets the btn
}
Now, in my other method, which is called by another controller, it does not work
- (void)callChildChange {
...
// remove old btn
UINavigationItem *thisNavBar = [self skemaNavigationItem];
thisNavBar.rightBarButtonItem = nil; // does not work?
}
There is nothing wrong with the method, it runs just fine, but the nav btn item does not get removed ?
skemaNavigationItem is a Navigation item, declared in the .h file which links the navigation item i made via the storyboard.

Your UI items need to be added to your code (by ctrl-dragging) in the header file (.h) so they can be publicly accessed from other classes/view controllers.
Presuming you've done this, hiding a UI item is best done by using
relevantClass.yourViewObject.hidden = YES;
or if you really need to delete it for good,
[relevantClass.yourViewObject.view removeFromSuperView];
Edits
Options for changing target method:
Declare #property (nonatomic, assign) BOOL myButtonWasPressed; and:
- (IBAction) myButtonPressed
{
if (!self.myButtonWasPressed)
{
// This code will run the first time the button is pressed
self.myButton.text = #"New Button Text";
self.myButtonWasPressed = YES;
}
else
{
// This code will run after the first time your button is pressed
// You can even set your BOOL property back, and make it toggleable
}
}
or
- (IBAction) myButtonWasPressedFirstTime
{
// do what you need to when button is pressed then...
self.myButton.text = #"New Button Text";
[self.myButton removeTarget:self action:#selector(myButtonPressedFirstTime) forControlEvents:UIControlEventTouchUpInside];
[self.myButton addTarget:self action:#selector(myButtonPressedAgain) forControlEvents: UIControlEventTouchUpInside];
}
- (IBAction) myButtonWasPressedAgain
{
// this code will run the subsequent times your button is pressed
}

Related

IOS: How to Reset Action of UIBarButtonItem after it has been created?

I have some code that creates barbuttonitem Edit and if you click it and begin editing, changes the button to Done.
When I first create the button I set its action to Edit. However, once the user is editing, I want to change the action of the renamed button to Save.
I thought I had save firing but somewhere along the line it stopped working possibly when I added a method in the middle to enable and disable the button.
Can anyone suggest the proper way to change the action of a bar button item?
Here is my code:
//code to create button which sets action to gotoEdit method
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStylePlain target:self action:#selector(gotoEdit)];
self.navigationItem.rightBarButtonItem = editButton;
}
-(void) gotoEdit {
self.navigationItem.rightBarButtonItem.title = #"Done";
_editButton.target = self;
_editButton.action = #selector(save);//changes action to save method
//some other code to make a textview editable, change its background color and so forth.
}
-(void) save {
NSLog(#"save method firing");
}
//I added the following methods at about the same time the save method stopped firing but not sure if they are related. (Probably not but including them anyway.)
//detect change on screen
- (void)textViewDidChange:(UITextView *)textView{
self.didChange=YES;
[self updateSaveButton];
}
-(void) updateSaveButton
{
self.editButton.enabled = (_didChange == TRUE);
}
It is better to use a bool instead of adding and removing the button's action.
-(void) gotoEdit {
if(!isEditing){
// Prep for editing
self.navigationItem.rightBarButtonItem.title = #"Done";
isEditing = true;
}else{
// Prep for saving
self.navigationItem.rightBarButtonItem.title = #"Edit";
isEditing = false;
}
}
For future reference you can remove a button's selector like this:
[_editButton removeTarget:self
action:#selector(gotoEdit)
forControlEvents:UIControlEventTouchUpInside];

buttons showing (null) when clicked, even when disabled

I have some buttons on my storyboard that I removed all text from and which I later add text to programmatically, so when the application starts the buttons are invisible. However, if a user clicks any one of the buttons, all four of the buttons show (null) in the label section of the button. I thought this might be because the buttons were enabled, so I added this code in the initWithFrame method of the subclass of UIView where the buttons are a property however it didn't change anything.
Furthermore, I don't understand why clicking one of the buttons would show (null) in the label area of all four buttons.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.button1.enabled= NO;
self.button2.enabled= NO;
self.button3.enabled= NO;
self.button4.enabled= NO;
}
return self;
}
I then considered that maybe this initWithFrame method isn't getting run when I thought it was. I tried in the subview of UIView and didn't change result
-(id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
self.answerChoice1.enabled= NO;
self.answerChoice2.enabled= NO;
self.answerChoice3.enabled= NO;
self.answerChoice4.enabled= NO;
}
return self;
}
Can you explain why all four buttons are showing (null) if I click on any one of them?
it depends i think on the selector the button is calling, and also whether you are able to distinguish your buttons.
you can use button.tag property to distinguish between your buttons as below:
// declare and allocate
UIButton* button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
// set frame
button1.frame = frameButton1;
// add to view
[self.view addSubview: button1];
// properties from docs
// button1.enabled or button1.hidden or button1 setTitle.. here
// add selector
[button1 addTarget:self selector:#selector(buttonAction:) ..UIEventTouchUpInside];
// add identifier, integer in this case
button1.tag = 1;
// repeat for other buttons
// in your selector
- (void)buttonAction:(UIButton *)sender
{
// identify button
switch (sender.tag) {
case 0:
// perform action
[self doAction];
break;
//..
}
// perform shared actions
}

Two actions for one UIBarButtonItem?

I have an edit button, that I obtained through self.editButtonItem and I have set it as self.navigationItem.leftBarButtonItem, such that when it is pressed, a UITableView begins editing and it turns into a "Done" button. When pressed again the view stops editing and the button returns to its normal state.
I would also like an "add" button to turn into a "Clear" button with a different action linked to it when the edit button is pressed.
(Much like in the iPhone "Phone" app's favourites tab, just that the plus button turns into a clear button when the Edit button is pressed).
I would really like to obtain the edit action and style etc in this way (self.editButtonItem), but I would also like to have an extra selector linked to the edit button.
How should I go about doing this? I have tried to create a category for UIBarButtonItem, but I don't really know what I should do with that.
Thanks.
To create a button whose title can change, you can do the following:
Define an ivar for the button:
UIBarButtonItem *_btnAddClear;
In viewDidLoad:
_btnAddClear = [[UIBarButtonItem alloc] initWithTitle:#"Add" style:UIBarButtonItemStyleBordered target:self action:#selector(addClearAction:)];
_btnAddClear.possibleTitles = [NSSet setWithObjects:#"Add", #"Clear", nil];
Since you want this button's title to change when the Edit/Done button is tapped, you can add code like the following:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
_btnAddClear.title = editing ? #"Clear" : #"All";
}
And lastly, the button handler:
- (void)addClearAction:(UIBarButtonItem *)button {
if (self.editing) {
// perform "clear" action
} else {
// perform "add" action
}
}
Give tag of UIBarButton such like 101;
and in BarButton Method write following
-(void)barButtonMethod
{
UIBarButtonItem * myButton = (UIBarButtonItem *) sender;
if(sender.tag == 101)
{
yourBtn.tag = 102;
// Write Your first action method such like
[self ActionMethod1];
}
else
{
yourBtn.tag = 101;
// Write Your second action method such like
[self ActionMethod2];
}
}
You don't really need a new action for the editButtonItem.
There is a property that tracks if the UIViewController is in editing state.
#property(nonatomic, getter=isEditing) BOOL editing
In order to do what you want, you can implement the following method in your UITableViewController:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated]
//Do your thing
}

Strange behaviour of dynamically added UIBarButtonItem

I'm working on an application in which I'm adding UIBarButtonItem to UIToolbar dynamically. When User clicks on a bar button. I'm changing it's tint color to red.
But for some bar buttons it's not working and the application is crashing.
Here is my code:
#interface myClass : UIViewController
#property (nonatomic, retain) NSMutableArray *barButtonItems;
#property (nonatomic, retain) IBOutlet UIToolbar *toolBar;
#end
#implementation myClass
#sythesize barButtonItems, toolBar;
- (void)viewDidLoad
{
[super viewDidLoad];
barButtonItems = [[NSMutableArray alloc] init];
[self initToolBar];
}
//To set the tool bar
- (void)initToolBar
{
[self addBarItem:#"PlantDetails" actionName:#"createPlantDetails:"];
[self addBarItem:#"ElectricalEquipmentInventory" actionName:#"createInventory:button:"];
toolBar.items = barButtonItems;
}
//Create bar button item
- (void)addBarItem:(NSString*)barButtonName actionName:(NSString*)methodName
{
UIBarButtonItem *plantDetails = [[UIBarButtonItem alloc] initWithTitle:barButtonName style:UIBarButtonItemStyleDone target:self action:NSSelectorFromString(methodName)];
[barButtonItems addObject:plantDetails];
[plantDetails release];
plantDetails = nil;
}
//Changes the barbutton tintcolor when user selected
-(void)changeSelection:(UIBarButtonItem *)button
{
NSArray *tempArray = toolBar.items;
for(int loop = 0; loop<[tempArray count]; loop++)
[[tempArray objectAtIndex:loop] setTintColor:[UIColor blackColor]];
[button setTintColor:[UIColor redColor]];
}
//First bar button method
- (void)createPlantDetails:(UIBarButtonItem *)button
{
[self changeSelection:button];
NSLog(#"createPlantDetails");
}
//second bar button method
- (void)createInventory:(int)selectedIndex button:(UIBarButtonItem *)button
{
[self changeSelection:button];
NSLog(#"createInventory");
}
#end
Here my issue is the bar button with only one parameter in it's selector is working perfectly (createPlantDetails) but when I click on the bar button which have two parameter in it's selector (createInventory) the application is crashing on [button setTintColor:[UIColor redColor]]; of changeSelection method.
Crash log is something like: touches event have no method like setTintColor .
I searched a lot but couldn't find a solution. Please help me.
Thanks in advance
The method for the action property has to have one of the following three forms:
- (void)methodName;
- (void)methodName:(id)sender;
- (void)methodName:(id)sender withEvent:(UIEvent *)event;
You can't use any arbitrary format or custom parameters (the button wouldn't know what to pass for them).
The createPlantDetails: method works because it matches the second form.
The createInventory:button: method fails because it doesn't match any of the expected signatures.
Since your method has two parameters, when the button calls the method, the button passes a UIEvent object in the second parameter which in your method is named button.
In changeSelection:, it crashes when it tries to call setTintColor: because button is really a UIEvent and not the UIBarButtonItem (ie. the sender).

How can I disable multiple buttons?

I have 2 buttons on my view and i want to disable the first button when i click on an other button and disable the second when I click again on the button.
I have tried with this code
if (button1.enable = NO) {
button2.enable = NO;
}
So I have in a NavigationBar a "+" button and 5 disable buttons in my view.
When I push the "+" button I want to enable the first button and when I push again that enable the second…
Thanks
if (button1.enabled == YES)
{
button1.enabled = NO;
button2.enabled = YES;
}
else (button2.enabled == YES)
{
button2.enabled = NO;
button1.enabled = YES;
}
Is that what your looking for? It would be an IBAction for the other button.
button1.enable = YES should be button1.enable == YES
a better readable form: [button1 isEnabled]
You're saying
if (button1.enabled = NO) {
when you probably mean
if (button1.enabled == NO) {
= is the assignment operator, and == is the boolean equality operator. What you're doing at the moment is assigning YES to button1.enable, which obviously enables button1. Then, because button.enable is true, control enters the if's clause and enables button2.
EDIT: To answer your new question ("When I push the "+" button I want to enable the first button and when I push again that enable the second..."), let's say that you initialise the button states somewhere. In your #interface add an instance variable
NSArray *buttons;
so your interface declaration looks something like
#interface YourViewController: UIViewController {
IBOutlet UIButton *button1;
IBOutlet UIButton *button2;
IBOutlet UIButton *button3;
IBOutlet UIButton *button4;
IBOutlet UIButton *button5;
NSArray *buttons;
}
and then initialise buttons like so:
-(void)viewDidLoad {
[super viewDidLoad];
buttons = [NSArray arrayWithObjects: button1, button2, button3, button4, button5, nil];
[buttons retain];
for (UIButton *each in buttons) {
each.enabled = NO;
}
-(void)viewDidUnload {
[buttons release];
[super viewDidUnload];
}
Let's say you hook up the + button's Touch Up Inside event handler to plusPressed:. Then you'd have
-(IBAction)plusPressed: (id) button {
for (UIButton *each in buttons) {
if (!each.enabled) {
each.enabled = YES;
break;
}
}
}
Each time plusPressed: is called, the next button in the array will be enabled. (I'm writing the above away from a compiler; there may be syntax errors.)
You could also make buttons a property. I didn't, because other classes have no business accessing buttons.

Resources