1
votes

Problem:

I have a UIView that has a UITableView as a subview. The UIView has a UITapGestureRecognizer configured.

My Problem is that taps on the table are consumed by the UIView's gesture recognizer. The result is the table view never gets to see taps.

How can I either make the recognizer fail when a point is within the table's frame OR make the table the default consumer of the tap.

I have tried (as the code examples show) a number of methods pointInside:withEvent, hitTest:withEvent but can't quite figure out how to do it.

Here is code representing the problem: Controller:

#import <UIKit/UIKit.h>
#import "ABCDTableView.h"

@interface ABCDFirstView : UIView
@property (nonatomic,strong) ABCDTableView *tableView;
@end

#import "ABCDFirstView.h"

@implementation ABCDFirstView
@synthesize tableView;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self awakeFromNib];
    }
    return self;
}

- (void)awakeFromNib
{

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
                                   initWithTarget:self action:@selector(viewTouch:)];

    [self addGestureRecognizer:tap];
}

- (void)viewTouch:(UIGestureRecognizer *)gesture {
    NSLog(@"view touched");
}


- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if (CGRectContainsPoint(self.tableView.bounds, point)) {
        NSLog(@"point in table point as well as view");
        return NO;
    }
    else if (CGRectContainsPoint(self.bounds, point)) {
        NSLog(@"point only in view");
        return YES;
    }
    NSLog(@"point not in view");
    return NO;
}


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *view    = [super hitTest:point withEvent:event];
    NSLog(@"view hittest res: %@",view);

    return view;
}
@end

TableView

#import <UIKit/UIKit.h>

@interface ABCDTableView : UITableView
    <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) NSArray *list;


@end



#import "ABCDTableView.h"

@implementation ABCDTableView
@synthesize list;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self awakeFromNib];
    }
    return self;
}

- (void)awakeFromNib
{
    self.delegate   = self;
    self.dataSource = self;

    // create table list
    self.list       = [[NSArray alloc]
                       initWithObjects: @"one",@"two",@"three",@"four",@"five",
                       @"six", @"seven", @"eight", @"nine", @"ten", nil];



}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.list count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"cell";
    UITableViewCell *cell   = [self dequeueReusableCellWithIdentifier:cellID];

    if (cell == nil) {
        cell    = [[UITableViewCell alloc]
                   initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }

    cell.textLabel.text = [self.list objectAtIndex:[indexPath row]];

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"row selected");
}


@end

View

#import <UIKit/UIKit.h>
#import "ABCDTableView.h"

@interface ABCDFirstView : UIView
@property (nonatomic,strong) ABCDTableView *tableView;
@end

#import "ABCDFirstView.h"

@implementation ABCDFirstView
@synthesize tableView;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self awakeFromNib];
    }
    return self;
}

- (void)awakeFromNib
{

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
                                   initWithTarget:self action:@selector(viewTouch:)];

    [self addGestureRecognizer:tap];
}

- (void)viewTouch:(UIGestureRecognizer *)gesture {
    NSLog(@"view touched");
}


- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if (CGRectContainsPoint(self.tableView.bounds, point)) {
        NSLog(@"point in table point as well as view");
        return NO;
    }
    else if (CGRectContainsPoint(self.bounds, point)) {
        NSLog(@"point only in view");
        return YES;
    }
    NSLog(@"point not in view");
    return NO;
}


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *view    = [super hitTest:point withEvent:event];
    NSLog(@"view hittest res: %@",view);

    return view;
}
@end
1

1 Answers

3
votes

Use the UIGestureRecognizerDelegate method

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;

and check if the touch.view is the same view as the one that should receive the gesture recognizer.