I have made a custom cell.In each custom cell there are many button like 3 to 4 i want add tap gesture for each button inside that cell.So that i can uniquely identify which cell's button was clicked.I have searched a lot but didn't find any good solution.
Please tell.
you want to access the button you can directly access, no need of Gesture
do like
[yourButton1 addTarget:self action:#selector(selectButtonPressed1:) forControlEvents:UIControlEventTouchUpInside];
yourButton1.tag=indexPath.row;
[yourButton2 addTarget:self action:#selector(selectButtonPressed2:) forControlEvents:UIControlEventTouchUpInside];
yourButton2.tag=indexPath.row;
[yourButton3 addTarget:self action:#selector(selectButtonPressed3:) forControlEvents:UIControlEventTouchUpInside];
yourButton3.tag=indexPath.row;
[yourButton4 addTarget:self action:#selector(selectButtonPressed4:) forControlEvents:UIControlEventTouchUpInside];
yourButton4.tag=indexPath.row;
Method - 1
-(void)selectButtonPressed1:(UIButton*)sender
{
NSLog(#"selcted button1");
}
Method - 2
-(void)selectButtonPressed2:(UIButton*)sender
{
NSLog(#"selcted button2");
}
Method - 3
-(void)selectButtonPressed3:(UIButton*)sender
{
NSLog(#"selcted button3");
}
Method - 4
-(void)selectButtonPressed4:(UIButton*)sender
{
NSLog(#"selcted button4");
}
Lets say you have n number of buttons. And you have one butotn action method:
YOu need to connect this method to all of your n buttons (touch up inside), so that whenever you press a button, this method will get hit.
You can either give tag values for your buttons or you can recognise them by thier title
-(IBAction) nButtonActions:(id)sender{
if([[sender titleLabel] isEqualtoString:#"your button-1 title"]){
//call your method for button -1
}
//or you can do the same using sender.tag
}
use restoration identifier.
button.restorationIdentifier = #"Cell Number _ button tag";
for example
button.restorationIdentifier = [NSString stringWithFormat:#"%#", indexPath.row];
NSString* rowIndexStr = ((UIButton*)sender).restorationIdentifier;
Related
I have a table view with user posts that can be upvoted and downvoted. I have two custom buttons for the upvote and downvote in the cells, which I use like so:
// in cellForRowAtIndexPath:
[cell.upVote addTarget:self action:#selector(handleThumbsUp:) forControlEvents:UIControlEventTouchUpInside];
[cell.downVote addTarget:self action:#selector(handleThumbsDown:) forControlEvents:UIControlEventTouchUpInside];
//the methods
- (IBAction)handleThumbsUp:(ThumbsUpButton *)sender {
if (sender.selected == YES) {
[sender setSelected:NO];
} else {
[sender setSelected:YES];
}
}
- (IBAction)handleThumbsDown:(ThumbsDownButton *)sender {
if (sender.selected == YES) {
[sender setSelected:NO];
} else {
[sender setSelected:YES];
}
}
When the "Thumbs Up" button is selected, and the user changes his mind and presses "Thumbs Down", how can I deselect the "Thumbs Up" button in that same cell?
You should have a model that contains the "thumbs up/down" information; you should not be storing it in your views in the form of the button being selected or not.
When one of the buttons is tapped, your controller should update the model and refresh the view based on the state of the model.
(Some kind of binding system would make this easier: ReactiveCocoa is one such option (though it's much more than just model/view bindings); another, much simpler (shameless link to my own free code) is my own UIViewController+WSSDataBindings category.)
By #selector you can access a property of the button not another control of the cell in a button handler method.
So, You must have update whole cell on the button handler method and manually handle the selected state of buttons in cellForRowAtIndexpath delegate method of table.
For simplest solution (with minimum structure change and code) it may be achieved with moving button action methods to your custom cell class. then add actions to upvote and downvote in cellForRowAtIndexPath:
// in cellForRowAtIndexPath:
[cell.upVote addTarget:cell action:#selector(handleThumbsUp:) forControlEvents:UIControlEventTouchUpInside];
[cell.downVote addTarget:cell action:#selector(handleThumbsDown:) forControlEvents:UIControlEventTouchUpInside];
Or you can directly set this methods from Nib file.
and then change the upvote / downvote methods like this.
//the methods
- (IBAction)handleThumbsUp:(ThumbsUpButton *)sender {
if (sender.selected == YES) {//upvote undone
[sender setSelected:NO];
} else {//upvote done
[self.upVote setSelected:YES];
[self.downVote setSelected:NO];//delesect downvote
}
}
- (IBAction)handleThumbsDown:(ThumbsDownButton *)sender {
if (sender.selected == YES) {//downVote undone
[sender setSelected:NO];
} else {
[self.downVote setSelected:YES];
[self.upVote setSelected:NO];//deselect upvote
}
}
also as Josh Caswell stated in his answer, you should have a data for the user's upvote and downvote in your dataModel you fill your cell. This is just a quick answer for this specific case, but to support dataModel changes you can add reference to your model inside your cell and modify it inside this action methods for saving votes.
I have a tableviewController with a bunch of buttons on it, and when they are tapped I want to push to a new view controller, and I am using the prepareForSegue method and then using control drag in the story board.
In prepareForSegue I have
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showItems"]) {
}
And then a bunch of stuff that I am sending to the next view controller, so in the storyboard all of my buttons have the same identifier "showItems" which is giving me a warning of"Multiple segues have same identifer showItems" What is the best way to get rid of this warning? I still want all the buttons to do the same thing, is the a better practice for pushing the next viewController.
Thanks for the help in advance.
EDIT
- (IBAction)showItems:(id)sender{
[self performSegueWithIdentifier:#"showItem" sender:self];
}
I have connected all the buttons to the IBAction, but then where would I pass the data to the next view controller?
In PrepareForSegue I have
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIButton *senderButton=(UIButton *)sender;
NSInteger meal = senderButton.tag % 10;
}
But this throws exception unrecognized selector sent to instance 0x7fcc1a496880
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[DiningMealsTableViewController tag]: unrecognized selector sent to instance 0x7fcc1a496880'
You can create a single segue using control drag from the tableviewController to the other viewController and fire the segue in the IBAction of the button. You can create only one IBAction for all buttons and use the sender parameter to recognize the button.
You only need one segue identifier, which identifies the movement from one UIViewController to another. Then inside the "calling" UIViewcontroller (the UIViewController that owns the tableview and buttons) you can trigger that Segue with a custom function that each of your buttons will call.
Like this:
- (void)viewDidLoad {
[super viewDidLoad];
// Create the buttons and assign them unique tags
// and assign them a custom click handler
UIButton *button1 = [[UIButton alloc] initWithFrame:button1Frame];
button1.tag = 1;
[button1 addTarget:self action:#selector(handleButtonPress:) forControlEvents:UIControlEventTouchUpInside];
UIButton *button2 = [[UIButton alloc] initWithFrame:button2Frame];
button2.tag = 2;
[button2 addTarget:self action:#selector(handleButtonPress:) forControlEvents:UIControlEventTouchUpInside];
// Add the buttons to the view or to your UITableViewCell
[self.view addSubview:button1];
[self.view addSubview:button2];
}
- (void)handleButtonPress:(id)sender {
// get the tag you assigned to the buttons
// to identifiy which one was pressed
UIButton *btn = sender;
int tag = btn.tag;
NSLog(#"You clicked button with tag: %d", tag);
if (tag == 1){
NSLog(#"You clicked on Button1");
// Do something custom here.
} else if (tag == 2) {
NSLog(#"You clicked on Button2");
// Do something custom here.
}
// Now this is where all your buttons can call the same SegueIdentifier
[self performSegueWithIdentifier:#"showItems" sender:sender];
}
Obviously I don't know much about the structure of your application, and my example adds the buttons to the root view, in your app you would have this same setup, only attached to the buttons you placed in your UITableViewCell but this one way you can get away with having multiple buttons trigger the same seque without having to explicitly assign a seque identifier in multiple places. It has the added benefit of being able to perform custom functions for each button before calling -performSegueWithIdentifier:sender, allowing added flexibility to your app.
Hope this helps!
just wondering how to make a button "START" that when pressed triggers a function and the text changes to "STOP". then when pressed again the function will stop and the text changes back to "START"
Ive got the button already that starts the function. and i can handle changing the title, just not sure on what to use to make the 1 button have 2 functions
Add the IBAction method like:
- (IBAction)buttonTapped:(id)sender
{
UIButton *btn = (UIbutton *)sender;
NSString *title=btn.titleLabel.text;
if ([title isEqualToString:#"Start"])
{
//Start
}else
{
//Stop
}
}
Please try this:
- (IBAction) buttonAction:(id)sender
{
if([[(UIButton *)sender currentTitle]isEqualToString:#"START"])
{
[actionButton setTitle:#"STOP" forState:UIControlStateNormal];
//start the action here and change the button text to STOP
}
else if([[(UIButton *)sender currentTitle]isEqualToString:#"STOP"])
{
[actionButton setTitle:#"START" forState:UIControlStateNormal];
//stop the action here and change the button text to START
}
}
you have at least two options here:
Check for the title of your button and depending on the value call an action or the other.
Create two different buttons, each one with his action and show/hide them.
I create a project of the Multiple user can tapped on the different button.
Following problem may phase,
I implement the gestureRecognizer and it's proper work but how get the which button tapped by the user for that to access those button event's
following screen shows the button,
Following is the code for gestureRecognizer delegate method so, how to get the button event and how to manage it,
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
if ([touch.view isKindOfClass:[UIButton class]]) {
NSLog(#"Button is pressed");
if (tag == 1) {
NSLog(#"Button1 is pressed");
}
return NO;
}
return YES;
}
following method for the IBAction method to touch when the button tapped
-(IBAction)btnPress:(id)sender{
tag=[sender tag];
NSLog(#"%i",tag);
}
But here issue is first call the gestureRecognizer delegate method then IBAction method to how to solve this problem,
Thanks in advance for your valuable time spend on my problem,
Thaks and regards
Neon Samuel.
If the button is instance of UIButton, then you do not need to use gestureRecognizer at all.
Try to set addTarget:action to get callback when user click that UIButton:
[button1 addTarget:self action:#selector(btnPress:)];
[button2 addTarget:self action:#selector(btnPress:)];
If you have already set tag value to each button, then your IBAction method would work properly.
-(IBAction)btnPress:(id)sender{
NSInteger tag=[sender tag];
NSLog(#"%d",tag);
}
How do I set a tag for a button programmatically?
I later want to compare to tags for a conclusion
I've tried this
-(IBAction)buttonPressed:(id)sender{
NSLog(#"%d", [sender tag]);
}
but that just crashes the app.
Any other ideas?
You need to cast sender as a UIButton:
-(IBAction)buttonPressed:(id)sender{
UIButton *button = (UIButton *)sender;
NSLog(#"%d", [button tag]);
}
Edit: Regarding the message "unrecognized selector"...
Based on your error message, it's not able to call the buttonPressed method in the first place. Notice in the error message it is looking for "buttonPressed" (no colon at end) but the method is named "buttonPressed:". If you are setting the button target in code, make sure the selector is set to buttonPressed: instead of just buttonPressed. If you are setting the target in IB, the xib may be out of sync with the code.
Also, your original code "[sender tag]" should also work but to access button-specific properties, you'll still need to cast it to UIButton.
I know this is an old question and been answered many a time in other questions, but it came up in a google search as second from the top. So, here is the answer to why it was crashing. Change it to 'button.tag'
-(void)myMethod
{
UIButton *theButton = [UIButton buttonWithType:UIButtonTypeCustom];
[theButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchDown];
theButton.tag = i;//or whatever value you want. In my case it was in a forloop
}
-(void)buttonPressed:(id)sender
{
UIButton *button = (UIButton *)sender;
NSLog(#"%d", button.tag);
}
No need for casting. This should work:
-(IBAction)buttonPressed:(UIButton*)sender
{
NSLog(#"%d", [sender tag]);
}