UIScrollView + UIWebView = NO scrollsToTop

8

看起来这个问题可能有简单的解决方案,但我没有找到任何可以引导解决它的东西。我正在UIScrollView中使用UIWebView,并且点击状态栏(滚动内容到顶部)不起作用。

我制作了一个简单的测试应用程序,以查看是否真的是UIWebView的问题。而它确实是。

//  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];

所以,我认为可能有一些可以禁用的东西,让UIWebView不会干扰scrollToTop?或者有一些解决方法也不错。

有什么想法吗?

4个回答

7

昨晚我遇到了这个问题,直到在一条评论中找到了答案。原始帖子的想法是当你将UIWebView添加到UIScrollingView时,使用以下代码:

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

在UIWebView的第一个子视图声称是不是UIScrollView的子类的情况下,这似乎让我感到可疑。然而,由于UIScroller支持scrollsToTop属性,类型转换只是为了避开编译器警告:

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

编辑: 还有关于实际需要发生的地方的另一个快速说明:在webViewDidFinishLoad回调中。在UIWebView构建时调用它是不够的,因为此时UIWebView尚未创建其引起问题的子视图:

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

编辑 #2:

现在,在iOS 5中,正如在iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back中所述,使用UIWebView的新属性scrollView,对于不使用低于iOS 5.0的部署目标的项目,使ensureScrollsToTop实现变得不必要。


谢谢nivekastoreth,这个问题一直困扰着我。我只想指出ensureScrollsToTop中缺少一个'(',并提醒其他发现此问题的人设置webview的委托,以便调用webViewDidFinishLoad。 - Rob Lourens
这段代码是可以运行的,但你可能想要这样写: ((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = YES; - nc.
我对此的记忆有些模糊,但据我回想,问题在于您需要将scrollsToTop设置为NO,因为如果多个滚动视图返回YES(当它们通过子项向下链接)它实际上会禁用该功能。只有一个滚动视图返回YES时才能启用该功能。 - nivekastoreth

3
在iPhone OS中,如果当前视图控制器中有多个UIScrollView(或其子类,例如UITableView,UIWebView),系统无法确定应该将哪个UIScrollView滚动到顶部。
快速解决方法:对于您不希望支持scrollsToTop的所有UIScrollView,只需将scrollsToTop设置为NO,然后一切都可以完美运行。
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

默认情况下,Webviews 的 scrollsToTop 值为 YES。我为这个特定问题编写了一个简单的类。在我的应用程序中,我们有多个 Webviews 和 scrollviews。这使得所有操作都变得更加容易。

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

它基本上在除了你指定的那个滚动视图之外的所有其他滚动视图上将scrollsToTop设置为NO


0

我想分享我的经验,我在UIScrollView上添加了一个UIWebView,就像 h4xxr所说的

如果有多个滚动视图,则忽略scrollViewDidScrollToTop消息

因此,我找到了一个简单的方法来使它在webView上工作:只需将scrollView的scrollsToTop属性设置为false。

当点击状态栏时,它不会被scrollView拦截,并且webView会滚动到顶部!

    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];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接