Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cross Directional UIScrollViews - Can I Modify the Scrolling Behaviour?

Tags:

Here's how the scroll views work: One scroll view is paging enabled in the horizontal direction. Each 'page' of this scroll view contains a vertically scrolling UITableView. Without modification, this works OK, but not perfectly.

The behaviour that's not right: When the user scrolls up and down on the table view, but then wants to flick over to the next page quickly, the horizontal flick/swipe will not work initially - it will not work until the table view is stationary (even if the swipe is very clearly horizontal).

How it should work: If the swipe is clearly horizontal, I'd like the page to change even if the table view is still scrolling/bouncing, as this is what the user will expect too.


How can I change this behaviour - what's the easiest or best way?


NOTE For various reasons, a UIPageViewController as stated in some answers will not work. How can I do this with cross directional UIScrollViews (/one is a table view, but you get the idea)? I've been banging my head against a wall for hours - if you think you can do this then I'll more than happily award a bounty.

like image 902
Jordan Smith Avatar asked Sep 25 '13 00:09

Jordan Smith


2 Answers

According to my understanding of the question, it is only while the tableView is scrolling we want to change the default behaviour. All the other behaviour will be the same.

SubClass UITableView. UITableViews are subClass of UIScrollViews. On the UITableView subClass implement one UIScrollView's UIGestureRecognizer's delegate method

- (BOOL)gestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UISwipeGestureRecognizer *)otherGestureRecognizer
{
    //Edit 1
    //return self.isDecelerating;
    //return self.isDecelerating | self.bounces; //If we want to simultaneous gesture on bounce and scrolling
    //Edit 2
    return self.isDecelerating || self.contentOffset.y < 0 || self.contentOffset.y > MAX(0, self.contentSize.height - self.bounds.size.height); // @Jordan edited - we don't need to always enable simultaneous gesture for bounce enabled tableViews
}

As we only want to change the default gesture behaviour while the tableView is decelerating.

Now change all 'UITableView's class to your newly created tableViewSubClass and run the project, swipe should work while tableView is scrolling. :]

But the swipe looks a little too sensitive while tableView is scrolling. Let's make the swipe a little restrictive.

SubClass UIScrollView. On the UIScrollView subclass implement another UIGestureRecognizer's delegate method gestureRecognizerShouldBegin:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 
{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        CGPoint velocity = [(UIPanGestureRecognizer *)gestureRecognizer velocityInView:self];
        if (abs(velocity.y) * 2 < abs(velocity.x)) {
            return YES;
        }
    }
    return NO;
}

We want to make the "swipe is clearly horizontal". Above code only permits gesture begin if the gesture velocity on x axis is double than on y axis. [Feel free to increase the hard coded value "2" if your like. The higher the value the swipe needs to be more horizontal.]

Now change the `UiScrollView' class (which has multiple TableViews) to your ScrollViewSubClass. Run the project. :]

enter image description here

I've made a project on gitHub https://github.com/rishi420/SwipeWhileScroll

like image 95
Warif Akhand Rishi Avatar answered Sep 21 '22 07:09

Warif Akhand Rishi


enter image description here

Although apple doesn't like this method too much:

Important: You should not embed UIWebView or UITableView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.

I've found a great way to accomplish this.

This is a complete solution for the problem. In order to scroll the UIScrollView while your UITableView is scrolling you'll need to disable the interaction you have it.

- (void)viewDidLoad
{
    [super viewDidLoad];
    _myScrollView.contentSize = CGSizeMake(2000, 0);
    data = [[NSMutableArray alloc]init];
    for(int i=0;i<30;i++)
    {
        [data addObject:[NSString stringWithFormat:@"%d",i]];
    }

    UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    [self.view addGestureRecognizer:tap];
}

- (void)handleTap:(UITapGestureRecognizer *)recognizer
{
    [_myTableView setContentOffset:_myTableView.contentOffset animated:NO];
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
          scrollView.userInteractionEnabled = NO;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
          scrollView.userInteractionEnabled = YES;
}

To sum up the code above, if the UITableView is scrolling, set userInteractionEnabled to NO so the UIScrollView will detect the swipe. If the UITableView is scrolling and the user taps on the screen, userInteractionEnabled will be set to YES.

like image 28
Segev Avatar answered Sep 20 '22 07:09

Segev