How to pass multiple values into #selector( ) for a UIButton? - objective-c

In other words: I have one button with two events, how to capture UIControlEventTouchDown and UIControlEventTouchUpInside in the callback function setRedPos?
[btnRedPos addTarget:self action:#selector(setRedPos:) forControlEvents:UIControlEventTouchDown];// I want to pass in a value of 0
[btnRedPos addTarget:self action:#selector(setRedPos:) forControlEvents:UIControlEventTouchUpInside];// I want to pass in a value of 1
...
- (void) setRedPos:(UIButton*)btn
{
}

You can't pass arbitrary parameters via target/action. The first parameter is sender, and the second (if you set it up this way) is the event. You could use the event to tell what kind of event triggered it, like so:
[btnRedPos addTarget:self action:#selector(setRedPos:forEvent:)
forControlEvents:UIControlEventTouchDown];
[btnRedPos addTarget:self action:#selector(setRedPos:forEvent:)
forControlEvents:UIControlEventTouchUpInside];
- (void) setRedPos:(id)sender forEvent:(UIEvent*)event
{
UITouch* aTouch = [[event allTouches] anyObject];
if( aTouch.phase == UITouchPhaseBegan ) {
NSLog( #"touch began" );
}
else if( aTouch.phase == UITouchPhaseEnded ) {
NSLog( #"touch ended" );
}
}

Use two separate selectors.
- (void)setRedPosDown:(UIButton *)button {
[self setRedPos:button state:0];
}
- (void)setRedPosUp:(UIButton *)button {
[self setRedPos:button state:1];
}
[btnRedPos addTarget:self action:#selector(setRedPosDown:) forControlEvents:UIControlEventTouchDown];
[btnRedPos addTarget:self action:#selector(setRedPosUp:) forControlEvents:UIControlEventTouchUpInside];

The only two ways I know to achieve that in one method are:
1) the method zpasternack describes
2) Using two separate buttons one for the touch up one for the touch down and test the sender.
The first method is better in your case since it is with only one button object.
The second would be useful if you were looking for one method achieving the actions of different buttons.
Try to stick the closer to the physical representation. One button but two different actions? The the code has only one button and tests the actions.

Related

Show touch when clicked UIButton Objective-C

I have a UIButton that has only an UIImage set, when Clicked (long press) the images changes automatically with a shadow, What I want is that even if the button gets clicked but not with a long press the images should have the shadow. I already tried from IB to set the UIButton properties Reverse on Highlight and Shows Touch On Highlight but with no results
This is about UIControl Class. It's default to be with shadow. So if you wanna customize it, you should addTarget to your button to every action on UIButton like tapping,long press,touchUpInside and I think it s not about long press it's just you can't realize the difference on tapping.
in one of my project I customize my button actions like this:
buyButton = [[UIButton alloc] initWithFrame:CGRectMake(self.frame.size.width*3/4-2, 0, self.frame.size.width/4+4, self.frame.size.height)];
[buyButton addTarget:self action:#selector(buyButtonClicked:) forControlEvents:UIControlEventTouchDown];
[buyButton addTarget:self action:#selector(buyButtonNormal:) forControlEvents:UIControlEventTouchUpInside];
[buyButton addTarget:self action:#selector(buyButtonNormal:) forControlEvents:UIControlEventTouchUpOutside];
and methods of this like:
- (void) buyButtonClicked:(UIButton *) sender {
if ([self.backgroundColor isEqual:[Util UIColorForHexColor:#"fede32"]]) {
self.backgroundColor = [Util UIColorForHexColor:#"fdca2e"];
}
else if([self.backgroundColor isEqual:[Util UIColorForHexColor:#"cfd3dc"]]) {
self.backgroundColor = [Util UIColorForHexColor:#"c0c5d0"];
}
}
- (void) buyButtonNormal:(UIButton *) sender {
if ([self.backgroundColor isEqual:[Util UIColorForHexColor:#"fdca2e"]]) {
self.backgroundColor = [Util UIColorForHexColor:#"fede32"];
}
else if([self.backgroundColor isEqual:[Util UIColorForHexColor:#"c0c5d0"]]) {
self.backgroundColor = [Util UIColorForHexColor:#"cfd3dc"];
}
[delegate purchaseOffer:selectedOffer];
}
If you need more information about UIButton actions there are a lot of question on this site.

Creating control pad

I am trying to code a controller for an image view to move using buttons.
inside up button code :
-(IBAction)upButton:(id)sender{
mainChac.center = CGPointMake(mainChac.center.x, mainChac.center.y - 5);
}
code is working properly but I have to tap it repeatedly to keep moving up, I wanna know which method to call, to move it, while holding the up button.
edit :
-(void)touchDownRepeat{
mainChac.center = CGPointMake(mainChac.center.x, mainChac.center.y - 5);
}
-(IBAction)upButton:(id)sender{
[upButton addTarget:self action:#selector(touchDownRepeat) forControlEvents:UIControlEventTouchDownRepeat];
}
edit 2: solution
-(void)moveUp{
mainChac.center = CGPointMake(mainChac.center.x, mainChac.center.y - 5);
}
- (void)holdDown
{
NSLog(#"hold Down");
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(moveUp) userInfo:nil repeats:YES];
}
- (void)holdRelease
{
NSLog(#"hold release");
[timer invalidate];
}
-(IBAction)upButton:(id)sender{
[upButton addTarget:self action:#selector(holdDown) forControlEvents:UIControlEventTouchDown];
[upButton addTarget:self action:#selector(holdRelease) forControlEvents:UIControlEventTouchUpInside];
}
EDIT:
What you need to to have 2 events, one for while the button is pressed down and another for when the button is released like so:
[aButton addTarget:self action:#selector(holdDown) forControlEvents:UIControlEventTouchDown];
[aButton addTarget:self action:#selector(holdRelease) forControlEvents:UIControlEventTouchUpInside];
- (void)holdDown
{
NSLog(#"hold Down");
}
- (void)holdRelease
{
NSLog(#"hold release");
}
Have your hold down function start a loop, and your holdRelease stop the loop.
EDIT-2:
An easy way (but perhaps not the best way) to achieve this loop would be to use NSTImer scheduledTimerWithTimeInterval inside the hold down and invalidate it in the release method.
all of this stuff has been done before, please try googling this stuff. Here is a stackoverlfow question with an example: ios scheduledTimerWithTimeInterval for amount of time

Is it Possible to Change Action For UIButton?

I am trying to change Action For the UIButton in ios applicatio. I did Following Code
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:#selector(aMethodShow:) forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[view addSubview:button];
In particular Section I want to change Action for this Button .So i did this
[button addTarget:self action:#selector(aMethodHide:) forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Hide View" forState:UIControlStateNormal];
Unfortunately This code note Working?
I suggest before adding new target, first invoke removeTarget on UIbutton object then add new target with other action.
I think it will help you
[yourButton removeTarget:nil
action:NULL
forControlEvents:UIControlEventAllEvents];
[yourButton addTarget:self
action:#selector(yourAction:)
forControlEvents:UIControlEventTouchUpInside];
You can use same action target instead of using two target. In one target you have to differentiate like below
-(void)btnAction
{
if(target1)
{
// code for target 1
}
else
{
// code for target 2
}
}
Here target1 is BOOL value which value first set to be YES. And change its value NO whenever you want to perform target 2 code.
I hope this will helps You.
I made an app recently and i had the same situation, but i found another way to solve it so i decided to share my solution with people who may be in the same situation.
I'll try to explain what i did with the context of this question:
I added a tag to the button and i associated it with one of the functions that button needs to call (aMethodShow: for example).
button always call the same function (callSpecificFunc: for example). What callSpecificFunc: does is call either function aMethodShow: or aMethodHide according with the current button tag.
In the particular section in which the button needs to call a different function, i only change the tag of button.
Something like this:
NSInteger tagOne = 1000; //tag associated with 'aMethodShow' func
NSInteger tagTwo = 1001; //tag associated with 'aMethodHide' func
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:#selector(callSpecificFunc:) forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[view addSubview:button];
...
// in some part of code, if we want to call 'aMethodShow' function,
// we set the button's tag like this
button.tag = tagOne
...
//Now, if we want to call 'aMethodHide', just change the button's tag
button.tag = tagTwo
...
-(void) callSpecificFunc:(UIButton*)sender
{
NSInteger tagOne = 1000;
NSInteger tagTwo = 1001;
if([sender tag] == tagOne){
//do whatever 'aMethodShow' does
}else {
//do whatever 'aMethodHide' does
}
}
Of course it could be applied for more than 2 functions :)

UIButton created runtime in a loop, now I need a specific function depending on the button touched

I am creating some buttons and putting them inside a UIScrollView like this:
int i = 0;
while (i != numberOfButtons ) {
int updatetY = 160*i;
CGRect buttonFrame = CGRectMake(updatetY, 0, 160, 60);
UIButton *button = [[UIButton alloc] initWithFrame:buttonFrame];
UIImage *buttonImage = [UIImage imageNamed:#"bg.png"];
[button setBackgroundImage:buttonImage forState:UIControlStateNormal];
[button setTitle:[buttonsArray objectAtIndex:i] forState:UIControlStateNormal];
[button addTarget:self action:#selector(MYPROBLEM) forControlEvents:UIControlEventTouchUpInside];
[menuScrollView addSubview:button];
i++;
}
Now I need to build a method to capture which button is being touched, and run a specific bunch of code (see (MYPROBLEM).
Anybody knows what I can do to "trace" which button is being touched and then run a specific function?
something like:
-(void) buttonfunction
{
case ...
doThis
case...
doThat
}
thanks in advance.
You need to use the tag property of the uibutton control. It's a numeric id for the button. You can set a tag on the button based on the i variable in your loop, for instance:
button.tag=i;
Then in your button's action message, you would simply add the id of the button as a parameter and check its tag like so:
-(void) buttonFunction:(id)sender {
switch (sender.tag)
{
//code goes here
}
}
Hope this helps.

Adding context to a UI control or NSObject

It's great to be able to addTarget on a UIButton. I only wish there was some sneaky way I could attach state to the UIButton so that when the target method is invoked, I could magically pull that state (any id) from the sender.
Something like:
[button shoveMyObjectInThere:foo];
[button addTarget:self action:#selector(touchyTouchy:) forControlEvents:UIControlEventTouchUpInside];
Followed by:
-(void) touchyTouchy:(id) sender {
UIButton button = (UIButton*)sender;
id foo = [button getByObjectBack];
// do something interesting with foo
}
Would be great if UIButton had an 'id context' property where developers could shove stuff, but that doesn't seem to be the case. Objective-C is a very dynamic language though, so I wonder if there is some sneaky way I can add method or fields to an object at runtime?
You could try making an associative reference
#import <objc/runtime.h>
objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy);
objc_getAssociatedObject(id object, void *key);
What about something like setValue:forKey:, a part of the Key-Value coding feature of Objective-C?
So I just did a quick test and found some interesting results.
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Hello" forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
button.frame = CGRectMake(100, 100, 100, 100);
[self.window addSubview:button];
// ...
- (void)buttonClicked:(id)sender {
NSLog(#"button clicked %#", [sender class]);
}
This prints: button clicked UIRoundedRectButton
So it seems like this should be possible... Truth be told, I ran into some problems subclassing UIButton to get the full example working but this seems promising. :)
The official solution is to use the "tag" property:
[self.someMutableArray addObject:foo];
button.tag = self.someMutableArray.count - 1;
[button addTarget:self action:#selector(touchyTouchy:) forControlEvents:UIControlEventTouchUpInside];
Then:
-(void) touchyTouchy:(id) sender {
UIButton button = (UIButton*)sender;
id foo = self.someMutableArray[button.tag];
// do something interesting with foo
}
In most situations you'd use an enum or constant for the tag, but an array is obviously more flexible.