8
votes

It looks like a problem which could have simple solution, but I haven't found anything what could lead the way to it. I'm using UIWebView inside of UIScrollView and tapping on statusBar (to scroll content to top) is not working.

I've made simple test application to see if it's really UIWebViews fault. And it really is.

//  scrolls to top on status bar tap 
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);
[self.view addSubview:sv];

// doesn't scroll
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);

UIWebView *wv = [[UIWebView alloc] init];
wv.frame = CGRectMake(0, 0, 320, 100);
[sv addSubview:wv]; 

[self.view addSubview:sv];

So, I think maybe there's something I could disable to make UIWebView not to mess with scrollToTop? Or some kind of workaround also would be nice.

Any ideas?

4

4 Answers

7
votes

I ran into this last night until I finally found the answer buried in a comment to a comment. The idea of that original post is that when you add the UIWebView to your UIScrollingView, you use the following:

- (void) ensureScrollsToTop: (UIView*) ensureView {
    ((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = NO;
}

This seemed fishy to me since the first sub-view of a UIWebView claims to be a UIScroller which is not a subclass of UIScrollView. However, since UIScroller supports the scrollsToTop property, the cast just gives us a way past the compiler warning:

Class List:
    Class = UIScroller
    Class = UIView
    Class = UIResponder
    Class = NSObject
Supported Methods:
    ...
    Method _scrollToTop
    Method setScrollsToTop:
    Method scrollsToTop
    ...
Supported Properties:
    Property scrollsToTop

EDIT: Just another quick note about where this actually needs to occur: in the webViewDidFinishLoad callback. Calling it on UIWebView construction isn't good enough because at that time the UIWebView hasn't created it's child views yet, which are the ones causing the problem:

- (void)webViewDidFinishLoad:(UIWebView *) wv {    
    [self ensureScrollsToTop: wv];
}

EDIT #2:

now, in iOS 5, as noted in iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back use UIWebView's new @property scrollView, making ensureScrollsToTop implementation unnecessary for projects that aren't using deployment targets lower than iOS 5.0 .

3
votes

In iPhone OS, if there is more than one UIScrollView (or its subclass, for example UITableView, UIWebView) in the current viewController, the system doesn't know which UIScrollView should be scrolled to the top.

Quick fix: for all the UIScrollViews that you don't want to support scrollsToTop, just set the scrollsToTop as NO, then every thing works perfect.

self.scrollView1.scrollsToTop = NO;
self.scrollView2.scrollsToTop = NO;
self.scrollView1.scrollsToTop = YES; // by default scrollsToTop is set as YES, this line is not necessary
0
votes

Webviews by default will have YES for scrollsToTop-value. I've written a simple class for this specific issue. In my app we're having multiple webviews and scrollviews. This makes it all much easier.

https://gist.github.com/hfossli/6776203

It basically sets scrollsToTop to NO on all other scrollViews than the one you are specifying.

0
votes

I want to add my case, I add an UIWebView on an UIScrollView, as h4xxr said:

If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored

So, I get a simply way to make it work on webView: just set the scrollView·s scrollsToTop property false.

And when tap the status bar, it won`t got intercepted by the scrollView, and the webView scrolls to the top!

    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.frame = self.view.bounds;
    scrollView.scrollsToTop = false; //igore scrollView`s scrollsToTop
    [self.view addSubview:scrollView];

    UIWebView *webView = [[UIWebView alloc] init];
    webView.frame = scrollView.bounds;
    [scrollView addSubview:webView];