Adding actions to a button programmatically on iOS - ios

I am trying to add an action to buttons which I am creating programmatically:
[btn addTarget:self
action:#selector(indexAction)
forControlEvents:UIControlEventTouchUpInside];
This works fine. However, I now want to pass a variable (int k) to the indexAction method. I couldn't get this to work:
[btn addTarget:self
action:#selector([self indexAction:k])
forControlEvents:UIControlEventTouchUpInside];
I am sure I'm doing something wrong. This is the context of the above code:
-(void) initIndexButtons {
float buttonPadding = -8;
float buttonWidth = 23;
float buttonHeight = 80;
CGRect frame = CGRectMake(0,0,0,0);
for (int k=0;k<5;k++)
{
UIButton* btn = [[UIButton alloc] initWithFrame:frame];; btn.tag = k;
btn.frame = CGRectMake(0, k*(buttonPadding+buttonHeight), buttonWidth, buttonHeight);
UIImage *newImage = [UIImage imageNamed:#"index.png"];
[btn setBackgroundImage:newImage forState:UIControlStateNormal];
[btn addTarget:self
action:#selector(self indexAction:k)
forControlEvents:UIControlEventTouchUpInside];
}
}
-(void)indexAction:(int *)buttonTag
{
NSLog(#"buttonTag: %i", buttonTag);
}
EDIT:
I changed my code to:
// ...
[btn addTarget:self
action:#selector(indexAction:)
forControlEvents:UIControlEventTouchUpInside];
//[self indexAction:k];
[indexView addSubview:btn];
[indexView sendSubviewToBack:btn];
}
}
-(void)indexAction:(id)sender
{
NSInteger *tid = ((UIControl *) sender).tag;
NSLog(#"buttonTag: %i", tid);
}
But now I get the warning message that "Initialisation makes pointer from integer without a cast for the line NSInteger *tid = ((UIControl *) sender).tag;
EDIT:
This is the right line of code:
NSInteger tid = ((UIControl*)sender).tag;

Normally the method that a button calls takes one parameter:
(id)sender
Take a look at the question - how to pass a variable to a UIButton action

tag is an NSInteger not NSInteger*
change to
NSInteger tid = ((UIControl*)sender).tag;

The way to do it is to set:
-(void)indexAction:(id)sender
{
NSLog(#"Tag=%#"[(UIButton*)sender tag]);
}
and the call:
[btn addTarget:self
action:#selector(self indexAction:)
forControlEvents:UIControlEventTouchUpInside];
}
not really sure about my casting, haven't tested that, but I think it should work!
Best of luck.

Related

Adding multiple UIButtons to an UIView with a selector action

I've added some buttons to an UIView (via addSubview) programmatically. I’ve added to this button an #selector with a function. However, they appear in the view but when I do click, the last button works only.
Into my .h:
#property (nonatomic, strong) UIButton * myButton;
Into my .m
for(int i=0;i<5;i++){
myButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
myButton.frame = CGRectMake(55, 55*i, 30, 30);
myButton.tag = i;
myButton.backgroundColor = [UIColor redColor];
[myButton addTarget:self action:#selector(myaction:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:myButton];
}
-(void)myaction:(UIButton *)sender{
if(sender.tag == 0){
NSLog(#“uibutton clicked %ld", (long)sender.tag);
}
}
How do I add the action to all buttons? not for the last only...
This works fine:
- (void)viewDidLoad {
[super viewDidLoad];
for(int i=0;i<5;i++){
UIButton *myButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
myButton.frame = CGRectMake(55, 55*i, 30, 30);
myButton.tag = i;
myButton.backgroundColor = [UIColor redColor];
[myButton setTitle:[NSString stringWithFormat:#"%ld", (long)i] forState:UIControlStateNormal];
[myButton addTarget:self action:#selector(myaction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:myButton];
}
}
-(void)myaction:(UIButton *)sender{
NSLog(#"uibutton clicked %ld", (long)sender.tag);
}
The code you posted in your question appears to be "this is what my code looks like" rather than your actual code. That can cause problems when people try to help.
In the future, post your actual code.
Let's make it more dynamic by calculating the height of the button and adding padding based on the number of buttons.
:
-(void)viewDidLoad {
[super viewDidLoad];
NSInteger height = self.frame.size.height - 5*20; // 5 is the button count
and 20 is the padding
NSInteger buttonHeight = height/5;
for(int i=0;i<5;i++){
UIButton *myButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
myButton.frame = CGRectMake(55, buttonHeight*i+padding*(i+1), 150,
buttonHeight);
myButton.tag = i;
myButton.backgroundColor = [UIColor redColor];
[myButton setTitle:[NSString stringWithFormat:#"%ld", (long)i]
forState:UIControlStateNormal];
[myButton addTarget:self action:#selector(myaction:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:myButton];
}}
-(void)myaction:(UIButton *)sender{
NSLog(#"uibutton clicked %ld", (long)sender.tag);
}
You could make it more dynamic by calculating the height of the button like this:
NSInteger height = self.frame.size.height - 5*20;
NSInteger buttonHeight = height/5;

Create a function that is able to check the title of the button pressed

I have a loop for creating buttons dynamically.
for (int b = 0; b < _currentPlayerTeams.count; b++)
{
HNTeamObject *team = _currentPlayerTeams[b];
CGFloat buttonY = 168 + ((b + 1) * distanceBetweenButtons) - 23;
NSString *buttonTitle = [NSString stringWithFormat:#"%# %#",team.teamName, team.seriesName];
UIButton *button = [[UIButton alloc] init];
button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:[UIImage imageNamed:#"images.png"] forState:UIControlStateNormal];
button.titleLabel.textColor = [UIColor blackColor];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
button.backgroundColor = [UIColor clearColor];
[button addTarget:self
action:#selector(chooseTeamOne:)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle: buttonTitle forState:UIControlStateNormal];
button.titleLabel.text = (#"%#", buttonTitle);
button.frame = CGRectMake(labelAndButtonX, buttonY, 268.0, 46.0);
[self.view addSubview:button];
}
I need to make a function that can act as the selector that for each button that is created and look at the button's title. Since I am making the buttons in the loop they are local and do not appear in another function that I create. Any help would be appreciated. I apologize in advance because I am very new to coding and am not quite up to speed with what is going on. Thanks.
Each button will call the chooseTeamOne: function when it is pressed so I assume you want to get the buttons title in that method.
To do so, use the UIButton's title property:
NSLog(#"%#", button.currentTitle);
This will log the button's current title. What is important to note is that I am referencing "button" which is the instance of the UIButton which called the chooseTeamOne method. I am assuming chooseTeamOne takes a UIButton button as a parameter.
If your method takes an 'id' as a parameter you would need to cast the sent object to a UIButton like this:
- (IBAction)chooseTeamOne:(id)sender {
UIButton *button = (UIButton *)sender;
NSString *buttonTitle = button.currentTitle;
}
Do you need a separate selector to return the title? If not then..
I imagine that your chooseTeamOne function is something along the lines of:
-(IBAction)chooseTeamOne:(id)sender {
...do things...
}
in which case, just add
-(IBAction)chooseTeamOne:(id)sender {
UIButton *button = sender;
NSString *stringThatYouWant = button.titleLabel.text; //get the text on the button
...do things...
}

Method for creating buttons

I have custom button class "EHCheckBox". There are many buttons in my app, so i try to optimize my code and create button in one line instead of 10. In my view, in viewDidLoad I call method witch call method which create my buttons.
-(void)viewDidLoad
{
.....
[self buttons];
.....
}
-(void)buttons
{
[self addNewBut:pcswitch Title:#" Switch" Column:3 Position:5 Dropable:NO Hide:NO]
}
-(void)addNewBut:(EHCheckBox*)checkBoxName Title:(NSString*)checkBoxTitle Column:(int)checkBoxColumn Position:(int)checkBoxPosition Dropable:(BOOL)checkBoxDropable Hide:(BOOL)hide
{
checkBoxName = [EHCheckBox buttonWithType:UIButtonTypeCustom];
[checkBoxName setTitle:NSLocalizedString(checkBoxTitle, #"") forState:UIControlStateNormal];
checkBoxName.hidden = hide;
if (checkBoxDropable) {
[checkBoxName setBackgroundImage:[UIImage imageNamed:#"CheckButton1.png"] forState:UIControlStateNormal];
[checkBoxName setBackgroundImage:[UIImage imageNamed:#"CheckButtonSelect1.png"] forState:UIControlStateSelected];
}else{
[checkBoxName setBackgroundImage:[UIImage imageNamed:#"CheckButton.png"] forState:UIControlStateNormal];
[checkBoxName setBackgroundImage:[UIImage imageNamed:#"CheckButtonSelect.png"] forState:UIControlStateSelected];
}
int firstColX = 45;
int firstColY = 125;
int width = 140;
int height = 36;
int widhtTwo = 18;
int x = firstColX + (checkBoxColumn - 1)*(width+widhtTwo);
int y = firstColY + (checkBoxPosition - 1)*(height);
checkBoxName.frame = CGRectMake(x, y, 140, 50);
[self.view addSubview:checkBoxName];
}
hide = YES because i have other methods which unhides and hides buttons, but they doesn't works because in view my button is nil, and i don't understand why? Maybe my method should return these button? Thank you.
I cannot understand what's your goal and code here but I really suggest to use categories. In this case the could should look better and more organized.
So, for example, you can follow this approach.
#import <UIKit/UIKit.h>
#interface UIButton (Factory)
+ (UIButton*)buttonWithTitle:(NSString*)title column:(int)column position:(int)position dropable:(BOOL)dropable hide:(BOOL)hide;
#end
and
#import "UIButton+Factory.h"
#implementation UIButton (Factory)
+ (UIButton*)buttonWithTitle:(NSString*)title column:(int)column position:(int)position dropable:(BOOL)dropable hide:(BOOL)hide {
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
//[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitle:NSLocalizedString(title, #"") forState:UIControlStateNormal];
[button setHidden:hide];
if (dropable) {
[button setBackgroundImage:[UIImage imageNamed:#"CheckButton1.png"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"CheckButtonSelect1.png"] forState:UIControlStateSelected];
} else {
[button setBackgroundImage:[UIImage imageNamed:#"CheckButton.png"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"CheckButtonSelect.png"] forState:UIControlStateSelected];
}
int firstColX = 45;
int firstColY = 125;
int width = 140;
int height = 36;
int widhtTwo = 18;
int x = firstColX + (column - 1)*(width+widhtTwo);
int y = firstColY + (position - 1)*(height);
button.frame = CGRectMake(x, y, 140, 50);
return button;
}
#end
You can use this category like the following. You need to import #import "UIButton+Factory.h".
UIButton* button = [UIButton buttonWithTitle:#"test" column:1 position:1 dropable:YES hide:NO];
[viewWhereYouWantToAddTheButton addSubview:button];
A note. If you pass 0 to both column and position, your button will assume negative x and y. Hence, you won't see it.

Fetching the tag values on selector

I am working with the iphone project. In that i added 3 buttons with same selector name(i.e action). Now i am fetch the data from the database using the query. But it is showing me the data to 3rd button only when i am pressing any butoon out of three .
btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(80, 30, 200, 50);
[btn.layer setBorderWidth:0];
btn.tag = 1;
[btn setTitle:#"1" forState:UIControlStateNormal];
[btn addTarget:self action:#selector(detail:) forControlEvents:UIControlEventTouchUpInside];
btn.titleLabel.font = [UIFont fontWithName:#"Zapfino" size:14.0];
[scrollview addSubview:btn];
btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(80, 30, 200, 50);
[btn.layer setBorderWidth:0];
btn.tag = 2;
[btn setTitle:#"2" forState:UIControlStateNormal];
[btn addTarget:self action:#selector(detail:) forControlEvents:UIControlEventTouchUpInside];
btn.titleLabel.font = [UIFont fontWithName:#"Zapfino" size:14.0];
[scrollview addSubview:btn];
btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(80, 30, 200, 50);
[btn.layer setBorderWidth:0];
btn.tag = 3;
[btn setTitle:#"3" forState:UIControlStateNormal];
[btn addTarget:self action:#selector(detail:) forControlEvents:UIControlEventTouchUpInside];
btn.titleLabel.font = [UIFont fontWithName:#"Zapfino" size:14.0];
[scrollview addSubview:btn];
this is the action which i am using.
-(IBAction)detail:(id)sender
{
detailViewController *detailvc =[[detailViewController alloc]initWithNibName:#"detailViewController" bundle:Nil];
detailvc.btntxt = btn.tag;
NSLog(#"name of btn :%ld",(long)btn.tag);
[self.navigationController pushViewController:detailvc animated:YES];
}
In nslog also i am getting the tab of 3rd button only
please help me out regarding this issue...
You are assigning 1 tag to a button
btn.tag = 1;
add different tag to each button
--
Also in your detail: take the tag from the sender and not your instance variable
- (IBAction)detail:(UIButton *)sender {
detailViewController *detailvc =[[detailViewController alloc]initWithNibName:#"detailViewController" bundle:Nil];
detailvc.btntxt = sender.tag;
NSLog(#"name of btn :%ld",(long) sender.tag);
[self.navigationController pushViewController:detailvc animated:YES];
}
You set the tag number of all 3 buttons to the same value (1). You need to use different values if you want to be able to tell your buttons apart.
Use tag 1 for the first button, tag 2 for the second, and tag 3 for the third.
Use the sender variable to get the button that triggered the action:
-(IBAction)detail:(id)sender
{
UIButton *button = (UIButton *)sender;
NSInteger buttonTag = button.tag;
// etc
}
Also, give each button it's own tag
btn.tag = 2; // and 3
And don't use the btn variable in the action method. It will only ever contain the last set variable, which is the third button in this case.
just use ((UIButton)sender).tag instead of btn.tag
The main problem with your code is that you are using just single button object ( & initializing it three times & adding three different tags & adding it to subviews.), which looks like an ivar.
So even if you have added three different tags to a single object instance the recent most will be reflected & so you are getting just 3 as tag, all time.
btn = [UIButton buttonWithType:UIButtonTypeCustom];
....
btn.tag = 1;
.
.
btn = [UIButton buttonWithType:UIButtonTypeCustom];
...
btn.tag = 2;
.
.
btn = [UIButton buttonWithType:UIButtonTypeCustom];
...
btn.tag = 3
Instead you either don't use btn object in ur target method or you can have three different buttons for a good understanding.
UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
btn1.frame = CGRectMake(80, 30, 200, 50);
....
btn1.tag = 1;
.
.
UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
btn2.frame = CGRectMake(80, 80, 200, 50);
...
btn2.tag = 2;
.
.
UIButton* btn3 = [UIButton buttonWithType:UIButtonTypeCustom];
btn3.frame = CGRectMake(80, 130, 200, 50);
...
btn3.tag = 3
Rest you need to modify the code of the target method as
-(IBAction)detail:(UIButton *)sender
{
detailViewController *detailvc =[[detailViewController alloc]initWithNibName:#"detailViewController" bundle:Nil];
detailvc.btntxt = sender.tag;
NSLog(#"name of btn :%ld",(long)sender.tag);
[self.navigationController pushViewController:detailvc animated:YES];
}
I hope this will certainly help you.
-(IBAction)detail:(UIButton*)sender
{
if(sender.tag==1)
{
}
else if(sender.tag==2)
{
}
else if(sender.tag==3)
{
}
}

application Crash when assign multiple argu fun to dynamic button

for (int i=0;i<[tableDataSource count];i++)
{
NSDictionary *dict = [tableDataSource objectAtIndex:i];
rowText = [dict objectForKey:#"title"];
UIButton *btn = [UIButton buttonWithType: UIButtonTypeRoundedRect];
[btn setTitle:rowText forState:UIControlStateNormal];
[btn addTarget:self action:#selector(myActionbtnText:) forControlEvents:UIControlEventTouchUpInside];
btn.frame = CGRectMake(60, 40+2*(40*i), 200, 40);
btn.alpha = 0.81;
[self.view addSubview:btn];
}
I got error at assign Action to dynamic button my action is given Below, how to pass object/parameter when button event occurs.
-(void) myAction:(NSString *)btnText;
{
NSLog(#"%# Button Clicked",btnText);
}
Try this :
for (int i=0;i<[tableDataSource count];i++)
{
UIButton *btn = [UIButton buttonWithType: UIButtonTypeRoundedRect];
[btn setTitle:rowText forState:UIControlStateNormal];
[btn addTarget:self action:#selector(myActionbtnText:) forControlEvents:UIControlEventTouchUpInside];
btn.tag = i;
btn.frame = CGRectMake(60, 40+2*(40*i), 200, 40);
btn.alpha = 0.81;
[self.view addSubview:btn];
}
-(void) myAction:(UIButton*)sender {
NSDictionnary *dict = [tableDataSource objectAtIndex:sender.tag];
NSString* rowText = (NSString*)[dict objectForKey:#"title"];
NSLog(#"%# Button Clicked",rowText);
}
There are several things wrong with your solution.
UIButton does not respond to addTarget:action:withObject:forControlEvents: but rather addTarget:action:forControlEvents. This is why your application is crashing.
The selector should be #selector(myAction:). The parameter should not be included.
I'm pretty sure that it wouldn't work anyway since by the time the button is pressed rowText will be out of scope and no longer available. Which is why you should go with #MathieuF solution (Just make sure to specify the selector correctly).

Resources