Reputation: 21893
The app I'm building has LOTS of custom UIButtons laying over top of fairly precisely laid out images. Buttonish, controllish images and labels and what have you, but with a clear custom-style UIButton sitting over top of it to handle the tap.
My client yesterday says, "I want that to highlight when you tap it". Never mind that it immediately pushes on a new uinavigationcontroller view... it didn't blink, and so he's confused. Oy.
Here's what I've done to address it. I don't like it, but it's what I've done:
I subclassed UIButton (naming it FlashingUIButton).
For some reason I couldn't just configure it with a background image on control mode highlighted. It never seemed to hit the state "highlighted". Don't know why that is.
So instead I wrote:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self setBackgroundImage:[UIImage imageNamed:@"grey_screen"] forState:UIControlStateNormal];
[self performSelector:@selector(resetImage) withObject:nil afterDelay:0.2];
[super touchesBegan:touches withEvent:event];
}
-(void)resetImage
{
[self setBackgroundImage:nil forState:UIControlStateNormal];
}
This happily lays my grey_screen.png (a 30% opaque black box) over the button when it's tapped and replaces it with happy emptyness .2 of a second later.
This is fine, but it means I have to go through all my many nibs and change all my buttons from UIButtons to FlashingUIButtons. Which isn't the end of the world, but I'd really hoped to address this as a UIButton category, and hit all birds with one stone.
Any suggestions for a better approach than this one?
Upvotes: 4
Views: 8312
Reputation: 1957
I had the same problem after subclassing a UIButton (Swift 2). The subclassed "drawRect" function is NOT called when the user touches the UIButton, (even if the checkmark "Highlighted Adjusts Image" is checked in the storyboard). This may be due to the fact that it is a custom UIButton.
Anyway, it is simple to handle, by overriding "touchesBegan" and "touchesEnded" events. More could be done to handle all states of the button (like disabled). But here is the code.
Swift 2:
import Foundation
import UIKit
@IBDesignable
class ppButton: UIButton {
override func drawRect(rect: CGRect) {
if self.state != UIControlState.Highlighted {
//SKit is another class containing a function to draw the custom button
SKit.drawPpButton(0, width: rect.width-2, height: rect.height-2)
} else {
//SKit is another class containing a function to draw the custom button
SKit.drawPpButton(0, width: rect.width-20, height: rect.height-20)
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
self.setNeedsDisplay()
}
}
Upvotes: 0
Reputation: 1574
You can intercept the touches events with a gesture recognizer, and then programmatically add the recognizer to all your uibuttons. For instance:
//
// HighlighterGestureRecognizer.h
// Copyright 2011 PathwaySP. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface HighlightGestureRecognizer : UIGestureRecognizer {
id *beganButton;
}
@property(nonatomic, assign) id *beganButton;
@end
and the implementation:
//
// HighlightGestureRecognizer.m
// Copyright 2011 PathwaySP. All rights reserved.
//
#import "HighlightGestureRecognizer.h"
@implementation HighlightGestureRecognizer
@synthesize beganButton;
-(id) init{
if (self = [super init])
{
self.cancelsTouchesInView = NO;
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.beganButton = [[[event allTouches] anyObject] view];
if ([beganButton isKindOfClass: [UIButton class]]) {
[beganButton setBackgroundImage:[UIImage imageNamed:@"grey_screen"] forState:UIControlStateNormal];
[self performSelector:@selector(resetImage) withObject:nil afterDelay:0.2];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)reset
{
}
- (void)ignoreTouch:(UITouch *)touch forEvent:(UIEvent *)event
{
}
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
{
return NO;
}
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
{
return NO;
}
- (void)resetImage
{
[beganButton setBackgroundImage: nil forState:UIControlStateNormal];
}
@end
Hmm. I didn't test this code, so if it doesn't work, don't sue me, just comment and we'll work it out. I just wrote it real quick for reference. Even if it doesn't work, the logic should still be sound.
edit:
Forgot to add, the way you'd add the gesture recognizer to your button would be like so:
HighlighterGestureRecognizer * tapHighlighter = [[HighlighterGestureRecognizer alloc] init];
[myButton addGestureRecognizer:tapHighlighter];
[tapHighlighter release];
So basically you're declaring it, initializing it, and then adding it. After that, you'll want to release it, since the addGestureRecognizer retains it.
Upvotes: 4
Reputation: 12438
Do you have adjustsImageWhenHighlighted = YES
set on your buttons? The default is YES
, but maybe you changed it in the xib. It's the "Highlighted Adjusts Image" checkbox in the attributes inspector:
Upvotes: 2