9

I'm having a really hard time understanding delegates and object inheritance (if I may use this word) and I think I need a simple (or so I think) thing: catch scrollViewDidScroll event in UIWebView and get offset (basically, just to know if scroll is not on top/bottom, so I could hide navigation and tab bars).

Is there any way I could do it? I already using UIWebviewDelegate in my view controller to "shouldStartLoadWithRequest". Maybe I could some how use UIScrollViewDelegate too for scrollViewDidScroll? If yes, then how?

I really have trouble understanding delegates. I've red some articles, but still, in practice, I can't manage to use them.

Any help or info would be lovely.

Thank you in advance!

Wil Shipley
  • 9,343
  • 35
  • 59
sniurkst
  • 7,212
  • 5
  • 30
  • 30

7 Answers7

13

To retrieve scroll events on UIWebView I personnaly use this code to get the scrollview that is inside the UIWebView :

- (void) addScrollViewListener
{
    UIScrollView* currentScrollView;
    for (UIView* subView in self.myWebView.subviews) {
        if ([subView isKindOfClass:[UIScrollView class]]) {
            currentScrollView = (UIScrollView*)subView;
            currentScrollView.delegate = self;
        }
    }
}

It's working. You can also use it to call [currentScrollView setContentOffset:offSet animated:YES]; The only problem may be not to pass Apple code checking. I don't know yet since I'm still in coding phase.

[UPDATE] The app with this code is in the app store for 4 months now and used by 40 000 users. I didn't have any trouble [UPDATE]

CedricSoubrie
  • 6,657
  • 2
  • 39
  • 44
  • I can't see why this wouldn't pass: what's non-public API's are being used? – jkp Mar 09 '11 at 14:47
  • It's just a bit ugly to get the scrollview like this. Apple would have given a scrollView property on the webview if they wanted us to use it I think. But yeah, my app has been approved. – CedricSoubrie Mar 09 '11 at 15:21
  • I would assume the scrollview already has a delegate set... or may in a future iOS version. Does this not seem to be the case? – zekel May 04 '11 at 15:33
  • @zekel I'm using this code for a while and I didn't see any side effect yet. I'd say it's sure... but yeah future iOS could change things. – CedricSoubrie Jun 11 '11 at 19:31
7

You can use the following methods to solve your problem.

For getting the pageOffset:

int pageYOffset = [[webViewObj stringByEvaluatingJavaScriptFromString:@"window.pageYOffset"] intValue];

For getting the total scroll height of a webpage:

int scrollHeight = [[webViewObj stringByEvaluatingJavaScriptFromString:@"document.documentElement.scrollHeight"] intValue];

For scrolling the webpage to a particular offset:

[webViewObj stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.body.scrollTop = %d",scrollHeight ]];

Biranchi
  • 16,120
  • 23
  • 124
  • 161
4

Old thread, I know -

As of iOS 5.0 you can use

myAccountWebView.scrollview

to access content size and offset.

MweyaMutsvene
  • 543
  • 4
  • 15
4

I made a modification to detect the class with isKindOfClass. Works - but may have issues with Apple code checking as stated above.

UIScrollView* currentScrollView;
for (UIView* subView in terms.subviews) {
    if ([subView isKindOfClass:[UIScrollView class]]) {
        NSLog(@"found scroll view");
        currentScrollView = (UIScrollView *)subView;
        currentScrollView.delegate = self;
    }
}
2

There is a scrolling view in the UIWebView, but it a) isn't a UIScrollView, and b) is something Apple considers a private implementation detail (and you should too). I only really have two suggestions:

  1. File a bug with Apple asking them to expose more of the infrastructure of the web view, or at least add some more delegate methods by which we can be notified of these sorts of events.
  2. Add some JavaScript code to your page that listens from scroll events, and notifies your app of them.

The basic foundation of #2 is to load a fake URL, and have your web view delegate process (and abort!) that load. (This question has come up a few times here on Stack Overflow.)

UPDATE:

As of iOS 5, there is now a public scrollView property on UIWebView that you can use to customize scrolling behavior. The exact view hierarchy of the web view remains an undocumented implementation detail, but this gives you a sanctioned way to access this piece of it.

Sixten Otto
  • 14,816
  • 3
  • 48
  • 60
  • Thanks, for now I've ended up with different interface solutions for what I needed to do. So, there is no way one could access UIWebViews UIScroller and extract some offsets from it? – sniurkst Oct 22 '09 at 23:17
  • No documented/safe way, no. I'm sure that if you poke around in the UIWebView's view hierarchy with a debugger, you can probably come up with something, but it may break at any time. And Apple doesn't like undocumented APIs in the App Store. (OTOH, the JavaScript APIs inside the web view *are* well-documented and stable....) – Sixten Otto Oct 22 '09 at 23:23
  • It is an UIScrollView and you can set the delegate. There is not a bug. You assign it to the subview and implement the ScrollViewDelegate. – Nick Turner Feb 20 '13 at 14:23
1

It's a good question. UIWebView is not a subclass of UIScrollView, although I can see why one might think it is. That means using the UIScrollViewDelegate methods is not an option to do what you want, and the UIWebViewDelegate protocol does not respond to those scrolling event type of messages. I don't think there's an easy way to detect scrolling events in a web view.

No Surprises
  • 4,831
  • 2
  • 27
  • 27
1

I tired the delegate method and found it prevented the view from scrolling when the keyboard was shown. I found that by adding an observer you do not override the current delegate and will prevent you from effecting the webview performance.

for (UIView* subView in myAccountWebView.subviews) {
    if ([subView isKindOfClass:[UIScrollView class]]) 
    {
        NSLog(@"found scroll view");
        [((UIScrollView*)subView) addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
    }
}
Wombat
  • 316
  • 3
  • 5