Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIWebView delegate vertical scroll event to parent, if scrolled to top or bottom

I have an UIWebView in an UIScrollView, which is paginated. Basically I want to switch between different webviews with scroll / fling gestures. Horizontally it works fine. If the webview is scrolled to the "border of the page", the scroll/pan event is passed to the scrollview, so that the next page is shown. On the vertical axis, this does not work. There does not seem to be an event passed to the scrollview. It might be a problem with the bouncing, which I disabled, because I thought, it would consume the event. But even with bouncing disabled, this does not work.

I tested this before with TextViews in a scrollview, which worked, too. Might be a special behaviour of webviews.

Any idea, how I get this to work? Do I have to implement event listeners and pass the events manually to the scrollview?

Furthermore, if you have a better idea how to implement this kind of layout, let me know. As I said, I want to have a grid of different views, which can be changed by fling/scroll gestures. Similar to the AppStore app, where the details of an app can be scrolled vertically and the screenshots can be scrolled horizontally.

Cheers Henrik

like image 413
henrik Avatar asked Dec 07 '22 14:12

henrik


2 Answers

So, I figured it out.

First I set the delegate of the webview, so that I get scroll events and can check, if the webview is scrolled to top or bottom:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if([scrollView isEqual:webView.scrollView]) {
        float contentHeight = scrollView.contentSize.height;
        float height = scrollView.frame.size.height;
        float offset = scrollView.contentOffset.y;

        if(offset == 0) {
            webViewScrolledToTop = true;
            webViewScrolledToBottom = false;
        } else if(height + offset == contentHeight) {
            webViewScrolledToTop = false;
            webViewScrolledToBottom = true;
        } else {
            webViewScrolledToTop = false;
            webViewScrolledToBottom = false;
        }

        //NSLog(@"Webview is at top: %i or at bottom: %i", webViewScrolledToTop, webViewScrolledToBottom);
    }
}

Then I registered additional swipe gesture recognizers at the webview's scrollview:

swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeUp)];
swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
swipeUp.delegate = self;
[self.webView.scrollView addGestureRecognizer:swipeUp];
[self.webView.scrollView.panGestureRecognizer requireGestureRecognizerToFail:swipeUp];
swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeDown)];
swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
swipeDown.delegate = self;
[self.webView.scrollView addGestureRecognizer:swipeDown];
[self.webView.scrollView.panGestureRecognizer requireGestureRecognizerToFail:swipeDown];

Notice the calls to [self.webView.scrollView.panGestureRecognizer requireGestureRecognizerToFail:swipeUp];. Those are absolutely necessary, because without them, the pan gesture recognizer of the webview would always consume the events, before they reach the swipe gesture recognizer. Those calls change the priorities.

In the swipeUp and swipeDown methods, I calculate the position of the next "page" and scroll the parent scroll view to this position, if there actually is a next page.

Last thing is, to check, if the webview is scrolled to top or bottom and only accept the gestures in that case. Therefor you have to implement the delegate of the gesture recognizer:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if(gestureRecognizer == swipeUp) {
        return webViewScrolledToBottom;
    } else if(gestureRecognizer == swipeDown) {
        return webViewScrolledToTop;
    }

    return false;
}

You might also have to disable the scroll bouncing to make this work with webpages, which are so small, that they are not scrolled at all:webView.scrollView.bounces = false;

like image 172
henrik Avatar answered May 03 '23 03:05

henrik


Is it really the scrollview which scrolls vertically or is it the webview? I haven´t tried it myself, but maybe this will help...

webView.scrollView.scrollEnabled = NO; 
webView.scrollView.bounces = NO;

or ...

webView.userInteractionEnabled = NO;
like image 29
xapslock Avatar answered May 03 '23 03:05

xapslock