Ios – UIWebView scrollView not calling scrollViewDidScroll on touch

delegatesiosscrolluiscrollviewuiwebview

I'm developing for iOS 6, and I am working on a sort of toolbar at the top of a UIWebView that will recede as you scroll up on the UIWebView.

My thought was that I could set the delegate of the UIScrollView that's inside the UIWebView to send messages to my UIViewController, which will animate the constraints on the toolbar at the top to get it to shrink and move and so forth.

However, the scrollViewDidScroll: method does not seem to get called, which confuses me.

Now, there are a number of other questions on SO similar to this one, most of which seem to be people forgetting to set the delegate property on the scrollView…

Needless to say, I'm setting the delegate. Some code snippets:

SDDefinitionViewController.h:

@interface SDDefinitionViewController : UIViewController <UIWebViewDelegate, UIScrollViewDelegate>
...

SDDefinitionViewController.m:

...
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self loadDefinitions];

    // Grab a reference to the ScrollView so that we can set the delegate and then use those method calls to animate the top bar.
    self.scrollView = self.webView.scrollView;
    self.scrollView.delegate = self;
    self.lastScrollViewVerticalOffset = 0;
}
...
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // (Code) <= Never gets called
}
...

And, to top it off, I did some debugger console action:

(lldb) po self
$0 = 0x095c0600 <SDDefinitionViewController: 0x95c0600>
(lldb) po self.scrollView
$1 = 0x0954e8d0 <_UIWebViewScrollView: 0x954e8d0; frame = (0 0; 1024 596); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x954ec50>; layer = <CALayer: 0x954eab0>; contentOffset: {0, 0}>
(lldb) po self.scrollView.delegate
$2 = 0x095c0600 <SDDefinitionViewController: 0x95c0600>

So, the delegate is definitely set correctly, there's nothing being released randomly.

Finally, I programmatically called setContentOffset on self.scrollView and the delegate method did get called. But that's not really helpful, because I want to detect when the user is scrolling with a gesture.

So, what's the scoop on this? Why would the scrollView not be calling its delegate methods?

EDIT:

So, looking at my app with Reveal, I see that my UIWebView has as a subview a _UIWebViewScrollView, and beneath that there is a UIWebBrowserView. The UIWebBrowserView is exactly the same size as the UIWebView…

Could it be that the UIWebViewScrollView doesn't have a normal content view that it offsets and so on, that webkit is doing the scrolling or something?

Best Answer

As UIWebView internally implements UIScrollViewDelegate Methods. Its is unlikely that the UIScrollViewDelegate will get reassigned to other objects except the current UIWebView object. So, I found a small work around. You can subclass UIWebView implement the UIScrollViewDelegate methods in that class and don't forget to forward the method to super or else unexpected behavior may occur.

This is how I solved the above problem:

/////in WebView.h file
//////WebView is subclass of UIWebView
#import <UIKit/UIKit.h>

@interface WebView : UIWebView
 @property(nonatomic,weak) NSObject <UIScrollViewDelegate> *mScrollDelegate;
@end

//// in WebView.m file
#import "WebView.h"
@synthesize mScrollDelegate;
@implementation WebView

- (id)init
{
    self = [super init];
    if (self) {
        self.scrollView.delegate = self;
    }
    return self;
}

/////scrollViewDidScroll Method, Also I am forwarding it to super class UIWebView
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    [super scrollViewDidScroll:scrollView];
    if([self.mScrollDelegate respondsToSelector:@selector(scrollViewDidScroll:)]){
         [self.mScrollDelegate scrollViewDidScroll:scrollView];
    }
    NSLog(@"scrollViewDidScroll");
}

@end

And make sure your self.webView must be of type WebView. in SDDefinitionViewController.m

self.webView.mScrollDelegate = self;

Now your scrollViewDidScroll method in SDDefinitionViewController.m will get called

Related Topic