13

(edited for clarity)

I have a UITableView. On top of that is a UIView with a Pan gesture attached. This Pan swipes left and right to change the underlying table. I use the pan gesture's action method to move the table. That working fine.

However, the UIView & its Pan gesture interferes with up/down scrolling the UITableView. How can I send the up/down scrolling to the table and keep the left-right on the view's area?

 ---------------------------------------
 |                                     |
 |             ----------------------  |
 |             |                    |  |
 |             |                    |  |
 |             |                    |  |
 | UITableView |                    |  |
 |             |        UIView      |  |
 |             |          +         |  |
 |             |       PanGesture   |  |
 |             |                    |  |
 |             |                    |  |
 |             |                    |  |
 |             |                    |  |
 |             ----------------------  |
 |                                     |
 |                                     |
 ---------------------------------------

The method triggered by the Pan gesture is like this

 -(void)move:(UIPanGestureRecognizer*)sender
 {
     CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self.view];
     float xTest = fabsf(translatedPoint.x);
     float yTest = fabsf(translatedPoint.y);
     if ( xTest>yTest)
     {
         // Move table view left-right.. this works
     } else
     {
         // Send up-down scrolling gesture to table view????? How to?
     }
 }
cannyboy
  • 24,180
  • 40
  • 146
  • 252

7 Answers7

11

I just solved a similar problem, except it was for vertical pans instead of horizontal ones. I'm not 100% sure about your use case, so this may not be what your looking for, but it may lead you in the right direction.

I sub-classed UIPanGestureRecognizer, and implemented the touchesMoved method, and checked to see whether the gesture had a larger horizontal or vertical change. Below is a snippet. The credit belongs to a different stackoverflow post, but I cannot find the link at the moment. (Sorry in advance for the poor formatting, first time posting)

-(void)touchesMoved:(NSSet*) touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
if(self.state == UIGestureRecognizerStateFailed) return;
CGPoint currentPoint = [[touches anyObject] locationInView:self.view];
CGPoint prevPoint = [[touches anyObject] previousLocationInView:self.view];
moveX += prevPoint.x - currentPoint.x;
moveY += prevPoint.y - currentPoint.y;
if(!drag) {
    if(abs(moveY) > abs(moveX))
        drag = YES;
    else
        self.state = UIGestureRecognizerStateFailed;
}
}

-(void)reset
{
[super reset];
drag = NO;
moveX = 0;
moveY = 0;
}

In my parent view controller, which I believe would be the UITableView in this case, I also implemented the following. I think in your case, you'd want to return no if it's a horizontal pan.

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if([gestureRecognizer isKindOfClass:[VerticalPanGestureRecognizer class]])
{
    return YES;
}
return NO;
}

Let me know if any of this is unclear.

Good Luck!

BMcGlade
  • 169
  • 3
  • The parent view in my case is a UIViewController. I tried the above code but is still doesn't pass the scroll to the table. – cannyboy Oct 19 '12 at 10:46
3

UIGestureRecognizer has a property that prevents recognized gestures from forwarding their events to the view-hierachy - sounds as if that was the right option for you. Try that and set it towards NO on your gesture recognisers in question.

cancelsTouchesInView

A Boolean value affecting whether touches are delivered to a view when a gesture is recognized.

@property(nonatomic) BOOL cancelsTouchesInView

Discussion

When this property is YES (the default) and the receiver recognizes its gesture, the touches of that gesture that are pending are not delivered to the view and previously delivered touches are cancelled through a touchesCancelled:withEvent: message sent to the view. If a gesture recognizer doesn’t recognize its gesture or if the value of this property is NO, the view receives all touches in the multi-touch sequence.

Available in iOS 3.2 and later.

From UIGestureRecognizer reference.

Till
  • 27,559
  • 13
  • 88
  • 122
2

OK, the answer was to add the pan to the UITableView instead of the UIView. The I check to see whether the gesture's location is within the borders of the (now hidden in the xib) UIView, like so:

 - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
 {
     CGPoint translation = [gestureRecognizer locationInView:self.view];
     CGRect frame = self.slideTarget.frame;
     if (CGRectContainsPoint(frame, translation))
     {
         return YES;
     } else
     {
         return NO;
     }
 }

Boom.

cannyboy
  • 24,180
  • 40
  • 146
  • 252
1

I understand that you want the gesture within the UIView to be handled according to its direction (vertical -> scroll table, horizontal -> scroll UIView). I read -did not try- about this: The UISwipeGestureRecognizer has an attribute direction - from the docs:

The permitted direction of the swipe for this gesture recognizer.

Maybe that can help you?

EDIT: Oh, well, I did not recognize you were looking at a UIPanRecognizer (too much "swipe" there)... Maybe you can pass the gesture to the table when the direction of the panning is "vertical enough", as reported by translationInView:..?

virtualnobi
  • 1,140
  • 2
  • 11
  • 35
1

In your Pan gesture's method writ this:

- (void)pan:(UIPanGestureRecognizer *)gesture
{
    CGPoint translatedPoint = [gesture translationInView:self.tableView];

    if (ABS(translatedPoint.y) > 10.0f) {
        self.tableView.bounds = CGRectMake(0, -translatedPoint.y, 320, 460);
    }
    if (ABS(translatedPoint.x) > 10.0f) {
        // swipe left/right code...
    }
}

Here you imitate scrolling of your table view by changing it's bounds property. But this code will not bounce table view. This effect can be achieved by saving bounce property state at the beginning of pan gesture and then assigning this property when gesture will end.

tagirkaZ
  • 469
  • 7
  • 19
0

As I can get sense from your requirement that you need to scroll table when you are interacting another view. So view layers will be like as:

UINavigationController-->view (Navigation controller will have UITableViewController) UITableViewController (It will have UiTableView)

And In the end

UIView (UINavigationController.view subview UIView)

So you want that if you do pan(scrolling) on your UIView, then your TableView will scroll properly.

So you need to make a class of your required UIView(Lets suppose CustomView). Then implement following methods in your CustomView class.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = [super hitTest:point withEvent:event];

    // If the hitView is THIS view, return the view that you want to     receive the touch instead:
    if (hitView == self) {
        return _tableView;
    }
    else if ([hitView isKindOfClass:[UIButton class]]) {
        return hitView;
    }
    return _tableView;
}

If you have a button subview at your CustomView also. Then you will get selection on it also.

Pardon me for my bad explanation but I just found this solution for my problem and I want to share it with you.

Let me know if you need more explanation. I will explain later.

Mohd Haider
  • 673
  • 1
  • 5
  • 25
  • This code will actually send your control to TableView and you will not need to use UIPanGesture for perform table scrolling. – Mohd Haider Apr 02 '16 at 10:51
0

Implement the UIGestureReconizerDelegate method, named - gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:.

It return false by default, implement it and return true.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return true;
}

And, don't forget to set the gesture's delegate property.

// Set the delegate of the panGesture. For example
self.panGestureReconizer.delegate = ... //

From Apple doc

(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

Asks the delegate if two gesture recognizers should be allowed to recognize gestures simultaneously.

Return value

YES to allow both gestureRecognizer and otherGestureRecognizer to recognize their gestures simultaneously. The default implementation returns NO—no two gestures can be recognized simultaneously.

Discussion

This method is called when recognition of a gesture by either gestureRecognizer or otherGestureRecognizer would block the other gesture recognizer from recognizing its gesture. Note that returning YES is guaranteed to allow simultaneous recognition; returning NO, on the other hand, is not guaranteed to prevent simultaneous recognition because the other gesture recognizer's delegate may return YES.


Read more

Community
  • 1
  • 1
AechoLiu
  • 17,522
  • 9
  • 100
  • 118