a.scarlett
a.scarlett

Reputation: 77

What is the best way to get a UIView to respond to fast, rapid single taps?

I have a view that I want to have users able to toggle quickly. I have tried using UITapGestureRecognizer, but it doesn't pick up the taps quite as well as I would like. Are there any other approaches I should try?

Thanks!

Upvotes: 2

Views: 134

Answers (1)

FuzzyBunnySlippers
FuzzyBunnySlippers

Reputation: 3397

You can create your own UIView derived class and insert it as a subview of whatever view you are using to get "touch" input directly. I used it as an overlay on screens so that I could trigger screen changes, animations, an "I am done looking at this" input mechanism, etc.

This approach uses the touchesEnded override for UIView (see code), not UITapGestureRecognizer. This is "old school" objective-C and does not use ARC.

Here is the header file "TapView.h"

#import <UIKit/UIKit.h>


@interface TapView : UIView 
{
    SEL touchedCallback;
    id touchedCallbackTarget;
   UILabel* label;
}

@property(nonatomic,assign) SEL touchedCallback;
@property(nonatomic,retain) id touchedCallbackTarget;
@property(nonatomic,retain) UILabel* label;

-(void)respondToTap:(SEL)withCallback andTarget:(id)target;

@end

You create the class and call [tapView respondToTap....] to initialize it with your target. Something like this (in viewDidLoad):

- (void)viewDidLoad
{
   [super viewDidLoad];
   UIView* navView = [ViewUtilities SetNavigationTitle:@"Thing Tank" andSubtitle:@"Tap Here To Empty Tank" forView:self];
   CGRect frame = navView.frame;   
   CGRect tapFrame = CGRectMake(0, 0, frame.size.width, frame.size.height);
   TapView* tapView = [[[TapView alloc] initWithFrame:tapFrame] autorelease];
   [navView addSubview:tapView];
   [tapView  respondToTap:@selector(tapNavBar) andTarget:self];
   self._tapView = tapView;
}

This code was used to allow a user to "reset" a "Thing Tank" (think fish tank) in an App I wrote for the for the iPhone called Six Things (you can find it here).

Here is the selector function (it takes no arguments):

-(void)tapNavBar
{
   [[NSNotificationCenter defaultCenter] postNotificationName:[Constants NOTIFICATION_RESTART_BACKGROUND] object:nil];            
}

Here is the implementation, TapView.m.

#import "TapView.h"


@implementation TapView

@synthesize touchedCallback;
@synthesize touchedCallbackTarget;
@synthesize label;

-(TapView*)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if(self)
    {
        self.touchedCallback = nil;
        self.userInteractionEnabled = YES;

      UILabel *lbl = [[UILabel alloc] init];
      lbl.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
      lbl.backgroundColor = [UIColor clearColor];
      lbl.textColor = [UIColor whiteColor];
      lbl.textAlignment = UITextAlignmentCenter;
      lbl.font = [UIFont boldSystemFontOfSize:16];
      lbl.text = nil;
      lbl.adjustsFontSizeToFitWidth = YES;
      self.label = lbl;
      [self addSubview:lbl];
      [lbl release];
    }
    return self;
}


/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code.
}
*/

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if(self.touchedCallback != nil && self.touchedCallback != nil)
        [self.touchedCallbackTarget performSelector:self.touchedCallback];
}

-(void)respondToTap:(SEL)withCallback andTarget:(id)target
{
    self.touchedCallback = withCallback;
    self.touchedCallbackTarget = target;
}


- (void)dealloc
{
   self.label = nil;
   [super dealloc];
}


@end

Was this helpful?

Upvotes: 2

Related Questions