1
votes

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?

2

2 Answers

2
votes

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

1
votes

I'm going to answer my own question, even though the answer is stupid.

Another person working on the project with me, who set up the content of the UIWebView, found that the scroll view within the web view wasn't scrolling correctly. So he disabled the scrolling on the web view, then in the HTML stuck the -webkit-overflow-scrolling: touch; tag, which cause the webkit to scroll rather than the web view--although it looks about the same. The original problem he was trying to solve was that some of the divs, for whatever reason, had the CSS style overflow:hidden; which caused the divs to not actually size to their contents, and made the web view think the page was really small, and thus the scrolling didn't work.

This took me roughly 8 hours to solve, although I admit that time was added when my lack of knowledge in web development led me to literally hacking apart the CSS style sheet until I could figure out what property was causing divs to not auto-size to their contents.

Anyway, perhaps one day this will help someone.