Reputation: 2095
I have a TableView containing UITableViewCells, each with 6 buttons...
A UISwipeGestureRecognizer is added to each of the buttons like so:
- (void)awakeFromNib {
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRightSwipe:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
[_XXSButton addGestureRecognizer:rightSwipe];
[rightSwipe release];
rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRightSwipe:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
[_XSButton addGestureRecognizer:rightSwipe];
[rightSwipe release];
rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRightSwipe:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
[_SButton addGestureRecognizer:rightSwipe];
[rightSwipe release];
rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRightSwipe:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
[_MButton addGestureRecognizer:rightSwipe];
[rightSwipe release];
rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRightSwipe:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
[_LButton addGestureRecognizer:rightSwipe];
[rightSwipe release];
rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRightSwipe:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
[_XLButton addGestureRecognizer:rightSwipe];
[rightSwipe release];
rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRightSwipe:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
[_XXLButton addGestureRecognizer:rightSwipe];
[rightSwipe release];
}
- (void)handleRightSwipe:(UIGestureRecognizer *)gestureRecognizer {
UIButton *button = (UIButton *)[gestureRecognizer view];
[self zeroButton:button];
}
When the swipe is recognised, it calls the method zeroButton .
No matter which button I do the swipe on, the view retrieved is of the first button. I would have expected [gestureRecognizer view] to return the button the swipe was performed on. Any ideas why I always receive the gesture of the first button only?
I recognise that this code isn't the most elegant to start with, having to create 6 different UISwipeGestureRecognizer. I would have preferred to create the gesture on the UITableViewCell itself, and manually check if the swipe originated or passed over a particular button. Unfortunately, my attempt at this has proven unreliable. So if someone has a suggestion on how to implement that method instead would be even better (I'll post that "solution" later)
Thanks...
Upvotes: 1
Views: 2303
Reputation: 2095
Actually, it was an error in the zeroButton code that caused it to always reset the first button. I used the tag assigned to the button to determine which action to create. My tags were incorrectly set! silly me. So the code in my original question was actually correct.
Since I have amended the code as follow:
- (void)awakeFromNib {
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRightSwipe:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
rightSwipe.delegate = self;
[self addGestureRecognizer:rightSwipe];
[rightSwipe release];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIButton class]])
{
// only recognises gesture started on a button
return YES;
}
return NO;
}
- (void)handleRightSwipe:(UIGestureRecognizer *)gestureRecognizer {
// Determine which button received the right swipe
// Get the position of the point tapped in the UIViewCell co-ordinate system
CGPoint tapPoint = [gestureRecognizer locationInView:self];
NSLog(@"%.1f %.1f", tapPoint.x , tapPoint.y);
UIView *viewAtBottomOfHierarchy = [self hitTest:tapPoint withEvent:nil];
if ([viewAtBottomOfHierarchy isKindOfClass:[UIButton class]])
{
[self zeroButton:(UIButton *)viewAtBottomOfHierarchy];
}
}
This looks at where the swipe originate and determine which button it started into (if any)...
Upvotes: 1
Reputation: 69047
One alternative approach, since you are using UIButton
s would be using addTarget:action:forControlEvents:
on your buttons for the events:
UIControlEventTouchDragInside
UIControlEventTouchDragOutside
UIControlEventTouchDragEnter
UIControlEventTouchDragExit
and the do your handling in the action
method you specify.
It should not be difficult to "map" the branches within your gesture handling method to different methods (or just one method, if you like) inside of your class.
I understand this is not a completely satisfactory answer, since it gives up using gesture recognizers (and their facilities), but it could work for you.
As to why the gesture recognizer does not work correctly when applied to a UITableViewCell
(and possibly it also explains why only the first button seems to receive the gesture), the behavior you described in your comment, reminded me that UIScrollView
(base class of UITableView) is greedy with touches (not so much as a UIWebView
, though) and that this for sure has an impact on how touches are forwarded. So, I don't know if it works, but I found this in UIScrollView
:
delaysContentTouches
If the value of this property is YES, the scroll view delays handling the touch-down gesture until it can determine if scrolling is the intent. If the value is NO , the scroll view immediately calls touchesShouldBegin:withEvent:inContentView:. The default value is YES.
This could work or not, it could even make the UITableView not work at all, but it is easy to try out.
If this does not work and my previous hypothesis is still correct, a way around it would be subclassing UITableView
and overriding the touch related methods (e.g., touchesShouldBegin:withEvent:inContentView:
) so you can customize their behavior.
OLD and WRONG ANSWER:
It is my understanding the you can share one same gesture recognizer among different views, like this:
rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRightSwipe:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
[_LButton addGestureRecognizer:rightSwipe];
[_SButton addGestureRecognizer:rightSwipe];
[_XButton addGestureRecognizer:rightSwipe];
[rightSwipe release];
I don't know if this can solve your issue, since what happens in your case is that, no matter which button you swipe, it is always that first gesture recognizer that gets activated and this is pretty hard to explain since you have different buttons. This could possibly be related to some overlapping (I am guessing) among the buttons, or to the fact that all of your buttons are "embedded" in a table cell, so the swipe mechanism at a cell level interferes with the swipe mechanism at the sub-cell level, but I am not sure about it.
As an alternative approach, which is surely working, you could attach your gesture recognizer to the very table cell (you mentioned your attempt to attach it to the table view itself; attaching to the table cell will work).
Hope this helps.
Upvotes: 1