Anastasia Anastasia - 4 months ago 68
iOS Question

UIScrollView inside UIScrollView

I have a

UIScrollView
with another
UIScrollView
inside. They both are scrolled horizontally and have
pagingEnabled = YES
.
Assume that I started to scroll inner scroll view and reached the most right bound. And if I proceed scrolling in it, then the outer scrollView begins to move. I need to avoid this. Inner view should jump with rubber-band effect, outer should stay at it's place.

Hope it's clear, but here is a sketch:
enter image description here

I've tried to set
outerView.scrollEnabled = NO;
like this:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
outerView.scrollEnabled = NO;
}


, and it works exactly how I need, if to scroll just in innerView. OuterView is not scrolled anymore. But I have to set
scrollEnabled
back to YES somewhere for the case if I'd want to scroll outerView again.
I've tried to do it here:

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


, but than I'm getting the same problem: after reaching the the most right bound of innerView outerView scrolls instead of innerView jumps with rubber-band effect.

Any suggestions how to solve a problem?

Answer

UPDATE

This solution works always:

@implementation InnerScrollViewController <UIScrollViewDelegate, UIGestureRecognizerDelegate>

- (void)viewDidLoad
{
    UISwipeGestureRecognizer*   swipeGesture = [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)] autorelease];
    swipeGesture.delegate = self;
    [self.view addGestureRecognizer:swipeGesture];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    _outerScrollView.scrollEnabled = NO;
    return YES;
}

- (void)handleSwipe:(UIGestureRecognizer*)gestureRecognizer
{

}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{   
    _outerScrollView.scrollEnabled = NO;
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (!decelerate)
    {
        _outerScrollView.scrollEnabled = YES;
    }
}

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

@end

-----------------------------------------------------------------------

OLD ANSWER: doesn't work always

Here is how I solved the problem:

@implementation InnerView

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

- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
    return NO;
}

As I understand, self.delaysContentTouches = NO; makes all events to be delivered immediately, and - (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view prevents passing of these events by responder chain.