防止UIScrollView滚动超过特定点

4

我有一个UIScrollView,它有一些子视图,创建了约为7000的宽度内容。 现在我想让UIScrollView不再滚动超过2000。

我尝试使用以下代码:

[scrollView setContentSize:CGSizeMake(768.0, 2000.0)];  
[scrollView setClipsToBounds:YES];

但我仍然可以滚动到底部,我该如何防止这种情况发生?


1
也许你应该发布一些创建ScrollView及其内容的代码片段。我无法重现这个问题。 - Evgeny Aleksandrov
滚动视图实际上是 UIWebView 的一部分。UIWebView 是否不允许设置 contentSize? - Thizzer
你正在访问webView.scrollview吗?对我来说,仍然可以使用setContentSize。你是如何设置内容的? - Evgeny Aleksandrov
你是指设置内容的意思是什么? - Thizzer
你的内容是什么?只有URL请求吗? - Evgeny Aleksandrov
不,只是一个本地的HTML文件,使用loadHTMLString加载。 - Thizzer
7个回答

8

看起来webView在页面加载后会更改其scrollViewcontentSize

在初始化时,将自己设置为WebView的代理:

[webView setDelegate: self];

并添加这个方法:
- (void)webViewDidFinishLoad: (UIWebView *)webView {
    [webView.scrollView setContentSize: CGSizeMake(768.0, 2000.0)]; 
}

在我的测试用例中,它运行良好。

更新:

有时调用JavaScript方法不会触发webViewDidFinishLoad。因此,最通用的技术将是键值观察。

在init中:

[webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];

还有一种方法:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    UIScrollView * scrlView = (UIScrollView *) object;
    if ([keyPath isEqual:@"contentSize"]) {
        NSLog(@"New contentSize: %f x %f",scrlView.contentSize.width,scrlView.contentSize.height);
        if(scrlView.contentSize.width!=768.0||scrlView.contentSize.height!=2000.0)
        [scrlView setContentSize:CGSizeMake(768.0, 2000.0)]; 
    }
}

在dealloc情况下不要忘记移除观察者:

[webView.scrollView removeObserver:self forKeyPath:@"contentSize"];

用JavaScript修改页面内容会改变contentSize吗? - Thizzer
是的,JavaScript 可以更改 contentSize,并且不会触发 webViewDidFinishLoad。回答已更新以处理此问题的方法。 - Evgeny Aleksandrov

1

如果内容偏移量超过2000,您可以将其设置为2000,以便它不会超出边界。

实现此方法并将其设置为滚动视图的委托。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.contentOffset.x > 2000) {
        CGPoint offset = scrollView.contentOffset;
        offset.x = 2000;
        [scrollView setContentOffset:offset animated:YES];
    }
}

编辑:我刚刚尝试了这个方法,它可以正常工作。也许你需要检查一下为什么setContentSize:没有起作用?另外一个方法是创建一个高度为2000的视图,将你的内容视图放在其中,并将该视图作为滚动视图的子视图添加。

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 600, 7000)];
label.numberOfLines = 60;
label.font = [UIFont systemFontOfSize:100];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];

NSMutableString *str = [[NSMutableString alloc] initWithCapacity:300];
for (int i = 0; i < 60; i++)
    [str appendFormat:@"%d\n", i];
label.text = str;

[scrollView addSubview:label];
[scrollView setContentSize:CGSizeMake(600, 2000)];
[self.view addSubview:scrollView];

这会阻止用户滚动太远,但由于scrollViewDidScroll不是每个像素都调用一次,因此我得到了非常跳跃的效果。 - Thizzer

0

我相信你上面的代码应该可以正常工作。setContentSize将防止contentOffset变得更大。但是,如果用户已经滚动到该区域之外,您可能需要自己(一次)设置contentOffset(尝试将其重置为(0,0),例如)。

另外,您是否允许缩放? 如果您的缩放!= 1,则内容大小可能不是您想象的那样。 在修改内容大小之前,请尝试将缩放设置为1。


0

好的,首先,您的视图控制器必须实现UISCrollViewDelegate,并且您必须将您的控制器设置为UIScrollView的代理。

然后,在您的控制器中实现此代理方法:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    static float stopx = 2000.0f;

    if (scrollView.contentOffset.x >= stopx) {
        CGPoint stop = scrollView.contentOffset;
        stop.x = stopx;
        [scrollView setContentOffset:stop animated:NO];
    }
}

每当您通过2000 / stops值时,滚动视图应该被带回


0

正如其他人所说,实现uiscrollviewdelegate

实现这些方法:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

希望这能解决你遇到的跳跃问题。
注意,在这些方法中加入类似其他帖子的代码。
static float stopx = 2000.0f;

if (scrollView.contentOffset.x >= stopx) {
    CGPoint stop = scrollView.contentOffset;
    stop.x = stopx;
    [scrollView setContentOffset:stop animated:NO];
}

首先,性能可能会受到影响,如果是这样,请开始删除某些委托方法,直到获得所需的行为


0

除非我在你的问题上有什么误解,否则这很简单。将此添加到包含 Web 视图的视图控制器中。

- (void)viewDidLoad
{
    // other stuff
    self.webView.delegate = self;
    self.webView.scrollView.bounces = YES;
    // load your webView here
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    CGSize contentSize = self.webView.scrollView.contentSize;
    CGFloat maxContentWidth = contentSize.width;
    if (maxContentWidth > 2000) {
        maxContentWidth = 2000;
    }
    self.webView.scrollView.contentSize = CGSizeMake(maxContentWidth, contentSize.height);
}

0

很难在没有查看你的HTML代码的情况下给出具体答案,但我以前遇到过类似的问题,我认为实际上是你的UIWebview在滚动而不是ScrollView。在UIWebview的HTML代码中,你很可能会发现有超过容器大小的内容。WebView自然希望滚动。在我的情况下,它是在文本段落中的一个长URL。我也见过这种情况在垂直方向上发生。

你需要找到容纳你超过容器大小的HTML代码的元素,并在CSS中将溢出设置为隐藏。这可能是HTML中的body标签或html标签,或者你需要包装你的内容。

例如;

<div style="overflow:hidden">
    Overflowing text
</div>

如果不行的话,你可能需要尝试调整以下标签:
或者将容器 div 设置为 width:100% & height:100%;

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