Detecting when a custom UIButton has been pressed - iphone

I have created a custom UIButton (UIButton subclass) for my application. Within this button's implementation, how would I alter the background color when it is pressed? (It should revert to it's normal background when depressed. I am currently using Core Graphics to draw a gradient background.)
I have tried branching in drawRect: (checking for self.selected and self.highlighted, but no change occurs because drawRect is not being called on the touch event.
Any suggestions or code samples are appreciated.

Try calling [self setNeedsRedraw] in your touch event.
Asker provided a solution based on this answer and the comments below.
Solution
Used:
[self addTarget:self action:#selector(buttonPressed) forControlEvents:UIControlEventTouchDown];
[self addTarget:self action:#selector(buttonDepressed) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside | UIControlEventTouchCancel];
Where the selectors are custom functions that perform the background change.

Related

How to ensure selected state of subclassed UIButton is drawn even when touch happens fast

I have subclassed UIButton in order to do some custom drawing with CoreGraphics in drawRect:. In order to respond to touch events, I am adding these target/actions:
[self addTarget:self action:#selector(selectedButton:) forControlEvents:UIControlEventTouchDown | UIControlEventTouchDragInside];
[self addTarget:self action:#selector(deSelectedButton:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchDragOutside | UIControlEventTouchUpOutside];
And an example implementation is this:
- (void)selectedButton:(id)sender {
self.isSelected = YES;
[self setNeedsDisplay];
}
This works pretty well. The only problem is that if I touch down/up really fast, the action is still processed, but the selected/deSelected methods get called so quickly that the background is never updated. But it works well if I press down for a little longer.
What am I missing here? How can I make my background update for the slightest of touches? I have tried delaying the deSelect call to update the layout, but it has no effect.
i think you probably need to call setNeedsDisplay on the main thread:
[self performSelectorOnMainThread:#selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
(i don't think whether waitUntilDone is yes or no will make any difference?...)

Issues in setting UIButton title in its click event

I'm trying to change the title of a button when the user press on it with the following code:
- (IBAction) hideKB: (UIButton *) sender {
sender.titleLabel.text = #"↓";
}
But when I click the app crashes and I can't understand why.
Removing the sender stuff, the button works with no problems.
The correct method signature for an action is
- (IBAction)action:(id)sender
Your app is crashing because your object is being sent a message it doesn't understand.
Try replacing your code with something along the lines of:
- (IBAction)hideKB:(id)sender {
UIButton *button = (UIButton *)sender;
[button setTitle:#"↓" forState:UIControlStateNormal];
}
As you may notice I've also changed the line that sets the button title. This is because you should never manipulate a UIButton's titleLabel property directly, but rather you should be using the appropriate setter method as shown above.
Edit: To clarify, most controls will allow you to use dot notation to edit the text property of their titleLabel. However, UIButton instances support different titles (as well as images and background images) depending on the state they're in.
If you're wondering why a UIButton could be in one of several different states, a good example you often see is buttons that are "greyed out". What this means is that those buttons are in the UIControlStateDisabled state. You can find a list of all the possible states for a control in the documentation.
Try using
- (void)setTitle:(NSString *)title forState:(UIControlState)state
e.g.
[sender setTitle:"↓" forState:UIControlStateNormal];
you can try with:
[(UIButton *)sender setTitle: #"↓"" forState: UIControlStateNormal];
For more information, you can refer to setTitle:forState: in UIButton Class Reference
Hope this helps.

UIButton under hidden UILabel won't work

I have a large UILabel which I am using to cover a bunch of buttons while I do something else.
All I have set initially is myLabel.hidden = YES; so you can't see the UILabel but the UIButtons (below it) won't work anymore.
Is there another setting for the UILabel I can use to allow touches to go "through it" when it is hidden? Thanks.
why use a UILabel to cover your buttons.
just set
UIButton *button;
[button setUserInteractionEnabled:NO];
or
[button setUserInteractionEnabled:YES];
You can use addSubView and removeFromSuperview methods :
When you want to hide your UIButton with your UILabel :
[self.view addSubview:myLabel];
and the contrary :
[myLabel removeFromSuperview];
I am not sure why a hide is stopping the touch events on buttons. Anyways you can explicitly bring the buttons to foreground by the following calls.
[self bringSubviewToFront:button];
The simplest thing to use as a general way to hide or cover things just a straight UIView. set:
[myCoverView setUserInteractionEnabled:YES];
and it will intercept touches and block touches to the buttons below it.
It should stop blocking touches when you hide it or turn the alpha to 0.0;
You can always siwtch the covering views interaction to:
[myCoverView setUserInteractionEnabled:NO];
and touches will pass through it.
If there is some reason that you need the UILabel these methods will work with it also.
[myLabel setUserInteractionEnabled:NO].
Even if is hidden, your label will get the touches anyway. You have to disable that to achieve what u want.
I think you should hide your buttons instead of covering them with a label.
[yourButton setHidden = YES];
[yourButton2 setHidden = YES];
...

Touch Event on image , achieved by using UIButton but show up delayed compare to UIImageView

Sorry for the messy title, I just don't know how to describe the problem in a delicate way.
I'm writing a album-like app to display a bunch of image in my scrollview and do something when a image is touched.
I followed this question : how can i detect the touch event of an UIImageView and use button with background image to handle touch event.
My original method is using NSOperation to concurrently fetch image from internet and put it io a imageview and add to my scrollview, and the speed is quite ok because each imageview shows right after each NSOperation callback.
Then I change imageview to uibutton, the strange thing is that when a NSOperation callback, that button does not show in my view. They show up at once when all the NSOperation callback is done. That makes the user experience become unacceptable.
This is my NSOperation callback function, it will pass a button that contains the image fetched from internet
- (void)imageLoaded:(UIButton*)button;
{
NSLog(#"Done");
[button addTarget:self action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
The buttons will only displa after the last "Done" appear instead of one by one, is that normal? or I messed up something?
==== update ========
I think I'm running the NSOperation on my viewcontroller. I have a imageLoadOperation class, I'll pass my viewcontroller to it
imageLoadOperation *ilo = [[imageLoadOperation alloc] initWithURLString:[NSString stringWithFormat:#"link for the image"];
[ilo setParent:self];
[queue addOperation:ilo];
[ilo release];
And in the main function of imageLoadOperation I'll do
[parentViewController performSelectorOnMainThread:#selector(imageLoaded:) withObject:button waitUntilDone:NO];
Do you mean I need to move these code to my AppDelegate instead of running in my viewcontrollor?
You can use a button of custom type over your image view instead of using button with background image, or you can use touch event on an UIImageView
(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
What if instead of converting to a button you just allowed your UIImageView to handle the touch event?
To add a touch event to a UIImageView use the following format in your .m
UITapGestureRecognizer *newTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(newTapMethod)];
[_imageButtonName setUserInteractionEnabled:YES];
[_imageButtonName addGestureRecognizer:newTap];
then create the newTapMethod (or what ever you name it)
-(void)newTapMethod{
//...
}
hope that helps.

Two Problems I'm having with UIButton and UIView

I haven't been programming on the iPhone for very long, but I'm picking it up slowly by googling problems I get. Unfortunately I haven't been able to find an answer for these.
I have started a new View-based application in Xcode 3.2.2 and immediately added the following files: myUIView.m and myUIView.h, which are subclasses of UIView. In Interface Builder, I set the subclass of the default UIView to be myUIView.
I made a button in the drawRect method.
Problem one: The title of the button only appears AFTER I click the screen, why?
Problem two: I want the button to produce the modalview - is this possible?
The code is as follow:
#import "myUIView.h"
#implementation myUIView
- (void)drawRect:(CGRect)rect {
// Drawing code
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(0,0,100,100);
[button setTitle:#"butty" forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
-(void)buttonPressed:(id)sender{
NSLog(#"Button pressed");
//present modal view somehow..?
}
I can't see how to post attachments, but if anyone thinks it will help I can upload the source.
Many thanks,
Andy
drawRect: is for custom drawing. You won't often need to do that. Your button won't be drawn until it gets sent drawRect:, probably in the next iteration of the run loop (ie, when you click on the view).
If you want a button on your view, either drag it there using IB, or move the code from drawRect: to viewDidLoad.
You present a modal view from a view controller by:
[self presentModalViewController:viewController animated:YES];
Do this in the action method your button sends to your view controller. This should indicate to you that you need to take a look at your application design.