I have a class like this,
#interface event
{
NSString *name;
UIButton *button;
}
In my view controller i am having several objects of event class, and i added all the buttons of those event objects to the view controllers class(self.view)
-(void) buttonPressed:(id) sender
Now i am handling the touchevent in my view controller as given above, now how can i identify the event object to which the pressed button(sender) belongs to.
You can simply compare the button property of the event object to the sender parameter of your action method. Assuming that your event objects are simply member variables of your view controller, your buttonPressed code might look something like this:
- (void)buttonPressed:(id)sender {
if (sender == event1.button) {
NSLog(#"Button pressed for event1");
}
else if (sender == event2.button) {
NSLog(#"Button pressed for event2");
}
}
Obviously you'll have to declare button as a #property of your Event object.
You should add a tag to your objects like:
myObject.tag = 1;
Then, in your buttonPressed method do something like
if(sender.tag == 1){
//...doSomething
}
Related
is there a way to pass a boolean to the addClicked method beside using button.tag for the code below?
[cellview.buttonAdd addTarget:self action:#selector(addClicked:) forControlEvents:UIControlEventTouchUpInside];
-(void) addClicked:(id)sender {
}
THanks in advance.
if you want to add a integer property , you can use tag.
if you want to add a nonInteger property , you must use a category with Associative References,the inheritting UIButton can not post property at all.
you can see this :
Subclass UIButton to add a property
Try something like this:
-(void) addClicked:(id)sender
{
UIButton * button = (UIButton*)sender;
NSLog(#"Button Tag: %i", button.tag);
}
Not sure what you mean by pass Boolean.
Short answer: You cannot pass extra information into the method directly.
Why would you want to do that anyway though? What does the button "know" that it would need to communicate, other than the fact that it was clicked?
The way this should be done is via an instance variable in the class that implements the click handler.
If you really must maintain state inside the button itself, subclass it:
#interface CustomButton : UIButton
#property (nonatomic, assign) BOOL myBoolValue;
#end
/* ... */
- (void)addClicked:(id)sender
{
CustomButton *button = (CustomButton *)sender;
if (button.myBoolValue) {
// Whatever you want to do.
}
}
I work on a project for iPhone iOS 4 with Xcode 4.
I have subclassed a UIButton so that it intercepts single and double tap.
This is the final part of #implementation of the UIButton subclass, two instance methods where the taps are "recorded";
- (void) handleTap: (UITapGestureRecognizer *) sender {
NSLog(#"single tap");
}
- (void) handleDoubleTap :(UITapGestureRecognizer *) sender {
NSLog(#"double tap");
}
A button instance is created in nib and all works OK: it intercepts single tap and double tap and output the NSLog.
Now the question: I have in my ViewController two methods (resetAllFields and populateAllFields) and I need that single tap execute resetAllFields and double tap execute populateAllFields.
How can I do? Where do I put the call?
Thank you.
If you want to handle the behavior in the ViewController the typical solution is to add a #protocol in your custom button class that defines methods for handling the single and double taps.
i.e. in your CustomButton.h
#protocol CustomButtonDelegate <NSObject>
- (void)button:(CustomButton *)button tappedWithCount:(int)count;
#end
You then have a delegate that implements this protocol in your custom button class and call those methods on the delegate when your taps are detected.
i.e. in your CustomButton.h
id <CustomButtonDelegate> _delegate;
in your methods in the implementation:
- (void) handleTap: (UITapGestureRecognizer *) sender {
NSLog(#"single tap");
[self.delegate button:self tappedWithCount:1];
}
- (void) handleDoubleTap :(UITapGestureRecognizer *) sender {
NSLog(#"double tap");
[self.delegate button:self tappedWithCount:2];
}
Your View Controller than implements the protocol methods and sets itself as the custom button's delegate.
ie. in your ViewControllers implementation
- (void)button:(CustomButton *)button tappedWithCount:(int)count {
if (count == 1) {
[self resetAllFields];
} else if (count == 2) {
[self populateAllFields];
}
}
Since you are using Interface Builder to set the custom button you can assign your view controller as a delegate in there or in the ViewDidLoad.
I have two .m files. The first is the main code, The second is a subclass of UIImageView so that i can detect touches.
In the main .m file I have added a progress bar and a customimageview both subviews of a scrollview.
What I need is that when a user touches the customimageview that the progress bar moves up and a double tap decreases the [Note: the customimageview has to have its touches recognised in the second .m because of them being in a subview of a scrollview and other controls are having to be handled]
In the main .m file I have a two methods:
- (void)pumpsingletap {
progbm.progress +=0.1;
}
- (void)pumpdoubletap {
progbm.progress -=0.1;
}
then in the subclassed uiimageview i have:
//inside touches method
if ([touch view].tag == 555) {
NSLog(#"pump touched");
switch ([allTouches count]) {
case 1: {
switch ([touch tapCount]) {
//---single tap---
case 1: {
NSLog(#"single pump touch");
[self performSelector:#selector(pumpsingletap) withObject:nil afterDelay:.4];
} break;
//---double tap---
case 2: {
NSLog(#"double pump touch");
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(pumpsingletap) object:nil];
[self performSelector:#selector(pumpdoubletap) withObject:nil afterDelay:.4];
} break;
}
}
}
}
So the NSlog's appear so the touch recognition isn't an issue. But the performSelector falls over. As the customimageview pumpsingletap doesnt work.
So how do i call the method in the subclass.
//update//
so I have added in the following code, in my subclass
mainMethod* callingMethod = [[mainMethod alloc] init];
[callingMethod performSelector:#selector(pumpsingletap) withObject:nil afterDelay:.4];
then in my main method for pumpsingletap i changed it to:
- (void)pumpsingletap {
NSLog(#"single pump method called");
progbm.progress +=0.1;
}
The NSLog for single pump method called appeared but the progress bar progbm - didn't move. so i have solved my calling issue - just need to now work out why the progress bar isnt moving!!
If I'm following the code correctly, you are performing the selector on self, but self is your derived UIImageView class (so you probably crash at that point?). You need to perform selector on the class in your main file. Pass a reference to that to your derived class. Alternately, you could create a delegate, implement it in your main class, pass your main class to the UIImageView and then call through the delegate (there are even other ways to do it (key-value observation), but one of these should work).
I'm not sure if this is the problem, but you don't need brackets around case statements. Also I don't get why you would make a switch within a switch. Just make an if-elseif-else statement, it'll probably be easier to understand.
Other than this, from what I understand, you have a view controller with both a progress bar and a customimageview as properties, and you have methods that should be called in response to certain actions, (tapping or double tapping the customimageview) but they're in the view controller. The usual way to solve this is by using the target action mechanism. UIControls implement the target action mechanism by encapsulating target-action pairs and storing them in a dictionary, keyed by the event type (UIControlEvent). Here's a slightly simpler version.
In the .h file for your subclass of UIImageView, before the #interface write this:
typedef enum {
ControlEventTap = 0,
ControlEventDoubleTap
} ControlEvent;
Then in the .m file add this before the #implementation:
#interface TargetActionPair : NSObject {
id target;
SEL action;
}
#property (nonatomic, assign) id target;
#property (nonatomic, assign) SEL action;
#end
#implementation TargetActionPair
#synthesize target, action;
#end
Then, add an NSMutableArray instance variable, (but not a property) and a - (void)setTarget:(id)t action:(SEL)a forEvent:(ControlEvent)e method to your customimageview implementation.
The method should look like this:
- (void)setTarget:(id)t action:(SEL)a forEvent:(ControlEvent)e {
TargetActionPair *tar_act = [[TargetActionPair alloc] init];
tar_act.target = t;
tar_act.action = a;
// actionsArray is the mutable array instance variable and must be allocated and set in the init method for customimageview.
[actionsArray replaceObjectAtIndex:(NSUInteger)e withObject:tar_act];
[tar_act release];
}
Then you can replace your touch handling code with:
if ([touch view].tag == 555) {
NSUInteger tapcount = [touch tapCount];
if (([alltouches count] == 1) && (tapcount <= [actionsArray count])) {
TargetActionPair *tar_act = [actionsArray objectAtIndex:tapcount-1];
[tar_act.target performSelector:tar_act.action withObject:nil afterDelay:.4];
if (tapcount == 2) {
TargetActionPair *tar_act2 = [actionsArray objectAtIndex:tapcount-2];
[NSObject cancelPreviousPerformRequestsWithTarget:tar_act2.target selector:tar_act2.action object:nil];
}
}
}
With this code you simply set the target and action for each control event in the viewDidLoad method of the view controller that contains the customimageview. So the calls would look like this:
[self.customimageview setTarget:self action:#selector(pumpsingletap) forEvent:ControlEventTap];
[self.customimageview setTarget:self action:#selector(pumpdoubletap) forEvent:ControlEventDoubleTap];
DON'T FORGET to release the actionsArray in your dealloc method and to be very careful about releasing the view controller since the customimageview doesn't retain it.
I hope this helps, best of luck on your app.
In the end I solved the issue by using NSNotificationCenter
I have multiple UIButtons in my app. I also use interfacebuilder. In my .h i have something like this
IBOutlet UIButton *button1;
IBOutlet UIButton *button2;
IBOutlet UIButton *button3;
- (IBAction)buttonPressed;
Then In my m i want to do something like this
- (IBAction)buttonPressed {
if (theButtonIpressed == button1)
{
// do something if
}
}
The problem is I don't have something called "theButtonIpressed" so I cant do this. What should my if statement look like? I don't want to make a -(IBAction) for each button. Is there something that I can determine which button was pressed? Thanks!
Thanks,
-David
You can also set the tag property for each button in the interface builder and then use it to find out which button was pressed.... This also means that you don't need to define all your button references (UIButton) and keep track of them in code....
- (void) doSomething:(id)sender {
int buttonPressed = [sender tag];
switch (buttonPressed) {
case 0:....
// etc
}
}
Define your - (IBAction)buttonPressed to:
- (IBAction)buttonPressed: (UIButton *) buttonIpressed
Then it will work.
- (IBAction)buttonPressed:(UIButton*)button
But if you're doing something different for each button then the proper way to do it is to create separate IBActions.
You can use tag values for each buttons
IBOutlet UIButton *button1;
button1.tag = 100;
IBOutlet UIButton *button2;
button2.tag = 200;
IBOutlet UIButton *button3;
button3.tag = 300;
- (IBAction)buttonPressed:(id)sender
{
if ([sender tag]==100)
{
NSLOG("button1");
}
else if([sender tag]==200)
{
NSLOG("button2");
}
else {
NSLOG("button3");
}
}
When an IBAction is called:
-(IBAction) onClick1: (id) sender;
What is passed in the sender? Since it's hooked up through the IB, I'm not really sure. My question is how to get the text of the button to be the passed object (NSString most likely) so that I could call it inside the action implementation.
-(IBAction) onClick1: (id) sender {
NSLog(#"User clicked %#", sender);
// Do something here with the variable 'sender'
}
The sender should be the control which initiated the action. However, you should not assume its type and should instead leave it defined as an id. Instead, check for the object's class in the actual method as follows:
- (IBAction)onClick1:(id)sender {
// Make sure it's a UIButton
if (![sender isKindOfClass:[UIButton class]])
return;
NSString *title = [(UIButton *)sender currentTitle];
}
It's actually:
-(IBAction) onClick1: (id) sender {
NSLog(#"User clicked %#", sender);
// Do something here with the variable 'sender'
}
sender is not a NSString, it's of type id. It's just the control that sent the event. So if your method is trigged on a button click, the UIButton object that was clicked will be sent. You can access all of the standard UIButton methods and properties programmatically.
-(IBAction)onClick:(id) sender {
UIButton *btn = (UIButton *)sender;
//now btn is the same object. And to get title directly
NSLog(#"Clicked button: %#",[[btn titleLabel] text]);
}
Simply write the following code
-(IBAction) getButtonTitle:(id)sender
{
UIButton *button = (UIButton *)sender;
NSString *buttonTitle = button.currentTitle;
NSLog(#"Button Title %#",buttonTitle);
}
Thats it... you have done!!!
Sender should be defined as type id, not int or NSString. The sender is the actual object that's calling the method; if you hooked it up to a button, it will be a UIButton, if it's a text field, a UITextField. You can use this to get information from the control (for example the text field's current string value), or compare it to an IBOutlet instance variable if you have multiple controls hooked up to the same action method.
You can just use the following to get the button label and determine which one was clicked:
NSLog(#"Clicked button: %#",[[sender titleLabel] text]);
To answer your question, the id is the object from the IB.
To fetch the text from the button:
NSLog(#"Date::%#",[btn titleForState:UIControlStateNormal]);