UIWebView嵌套在UIScrollView中

8
我的应用程序中有几个UIWebView视图在UIScrollView内。有时候我会使用UIWebView loadHTMLString:baseURL:方法加载HTML内容,这似乎并不会出现问题。但最近我开始使用loadRequest:方法来加载一些UIWebView实例的网址,一旦我这样做,每次滚动时都会出现以下错误:

* Terminating app due to uncaught exception 'CALayerInvalidGeometry',reason: 'CALayer position contains NaN: [nan nan]'

以下是相关的堆栈跟踪:

Thread 1, Queue : (null)
#0  0x01dd5caa in objc_exception_throw ()
#1  0x01f5da48 in +[NSException raise:format:arguments:] ()
#2  0x01f5d9b9 in +[NSException raise:format:] ()
#3  0x007e8c0d in CA::Layer::set_position(CA::Vec2<double> const&, bool) ()
#4  0x007def55 in -[CALayer setPosition:] ()
#5  0x037b07d3 in -[WebFixedPositionContent scrollOrZoomChanged:] ()
#6  0x00a5bfae in -[UIWebDocumentView _updateFixedPositionContent] ()
#7  0x00c66ff3 in -[UIWebBrowserView _updateFixedPositionContent] ()
#8  0x00a5b07e in -[UIWebDocumentView _didScroll] ()
#9  0x01fb6dea in -[NSObject performSelector:] ()
#10 0x01f207f1 in -[NSArray makeObjectsPerformSelector:] ()
#11 0x0091627d in -[UIScrollView(Static) _notifyDidScroll] ()
#12 0x009029ae in -[UIScrollView setContentOffset:] ()
#13 0x00909ac8 in -[UIScrollView _updatePanGesture] ()
#14 0x0090d3c0 in -[UIScrollView handlePan:] ()
#15 0x00b84e29 in _UIGestureRecognizerSendActions ()
#16 0x00b84133 in -[UIGestureRecognizer _updateGestureWithEvent:] ()
#17 0x00b853bf in -[UIGestureRecognizer _delayedUpdateGesture] ()
#18 0x00b87a21 in ___UIGestureRecognizerUpdate_block_invoke_0541 ()
#19 0x00b8797c in _UIGestureRecognizerApplyBlocksToArray ()
#20 0x00b803d7 in _UIGestureRecognizerUpdate ()
#21 0x008e51a2 in -[UIWindow _sendGesturesForEvent:] ()
#22 0x008e5532 in -[UIWindow sendEvent:] ()

我看过很多关于这个问题的问答,意识到苹果不鼓励这样做,但我没有看到任何提供替代方法的答案。

我的第一个问题:是否有其他方式可以实现相同的效果?

下面是我创建UIWebView的代码片段:

- (void) createWebView:(NSString*)url{
NSInteger requestedHeight = 480;
NSInteger requestedWidth = 640;

self.webContent = [[UIWebView alloc] initWithFrame: CGRectMake(0, self.frame.size.height, requestedWidth, requestedHeight)];
self.webContent.scrollView.userInteractionEnabled = NO;
self.webContent.scrollView.scrollEnabled = NO; 
self.webContent.scrollView.bounces = NO;

NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[self.webContent loadRequest:urlRequest];

[self addSubview:self.webContent];

NSInteger calculatedHeight = self.webContent.frame.origin.y + self.webContent.frame.size.height;
NSInteger calculatedWidth = self.webContent.frame.origin.x + self.webContent.frame.size.width;
if (calculatedHeight > self.frame.size.height || calculatedWidth > self.frame.size.width){
    self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, MAX(self.frame.size.width, calculatedWidth), MAX(self.frame.size.height, calculatedHeight + 5));
}    
}

如您所见,我禁用了UIWebView的滚动和用户输入。
我的第二个问题是:为什么UIWebView(或者说它的一个或多个子视图)在我明确禁用了滚动功能时仍然处理滚动?
我的第三个问题是:既然它似乎仍在处理滚动,是否有其他方法可以拦截或禁用发送到UIWebView的滚动通知?
如您所见,我实际上并不打算让用户与UIWebView的内容进行交互 - 只允许他们查看内容。
在这种情况下,可能的替代方案是在UIScrollView之外创建一个UIWebView,它对用户不可见,将其内容捕捉成图像,然后在UIImageView中显示内容。如果是这样,如何将UIWebView的内容捕捉成图像?
编辑: 我找到了一个非常简单的解决方案。基本上,加载您的UIWebView但不将其添加为子视图。当UIWebView完成加载时,使用下面的代码创建图像:
- (void)webViewDidFinishLoad:(UIWebView *)webView{
UIGraphicsBeginImageContext(self.webContent.bounds.size);
[self.webContent.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

[self.imageContent setImage:image];
}

我仍然希望听到问题1至3的答案。如果我们决定支持交互式UIWebView,这个解决方案将不起作用。

有什么建议吗?


你有关于这个问题更多的资讯吗? - hfossli
你是在尝试将UIWebView作为另一个UIScrollview的子视图添加吗?你添加了用于加载视频的子WebView吗?我真的不明白你想做什么!如果你能提供给我更多信息,也许我可以给你一些建议。 - Meera
我在我的项目中做过类似的事情,我想展示来自YouTube频道的视频,我通过在UIWebView中嵌入实现了这个功能。 - Meera
5个回答

2

你是在iOS模拟器还是实际设备上测试这段代码?

最近我在iOS 5.1模拟器上测试时遇到了同样的崩溃问题,但在运行5.1的iPad/iPhone上没有出现同样的崩溃问题。

iOS 6在设备和模拟器上都可以正常工作。

我认为这是由于iOS 6中UIWebView的更改所致,现在UIWebView已经被更改为异步绘制其内容。


1

在尝试使用以下代码设置属性时,请检查NaN值:

BOOL isNaN = isnan(your_Value);

当您能够正确处理这些值并运行代码时,最好找出为什么首先会发生这种情况(我猜测在获取要设置的值时进行了一些不可靠的计算)。

此外,这里解释了NaN:http://en.wikipedia.org/wiki/NaN


如果事情真的那么简单就好了。然而,这并没有真正回答我们的问题。是Webview计算出了一个无效的偏移量,而不是外部ScrollView。它基于来自外部ScrollView通知的信息计算NaN值。设置在外部ScrollView上的值都很好。 - hfossli

1

实际上,我只能建议尝试编写自己的“webview”类,其中包含自定义的带有NSURLRequest的NSURLConnection并在后台启动WebView以加载HTML字符串。我在应用程序中使用WebView遇到了很多问题,因此可能没有UIWebView loadRequest调用的解决方案。


你把我搞糊涂了。怎么回事?为什么? - hfossli

1

如果没有样本项目进行调试,这将很困难。因此,我不确定是什么原因导致了这个问题。我建议您再次检查帧计算。如果您的父UIScrollView在界面生成器中,请尝试关闭自动布局以查看是否有所不同(因为contentSize的工作方式不同)。

还有一些其他事情可以尝试:

[webview.scrollView.panGestureRecognizer requireGestureRecognizerToFail:myScrollView.panGestureRecognizer];

这将确保您的父级滚动视图始终优先于 WebView。因此,这可能会防止出现错误。

根据您使用 WebView 的方式,有几种情况可供选择:

  • 在 UIWebView 上调用 renderInContext 以获取屏幕截图并简单地使用 UIImage。处理完 UIWebView 后,实际上会使用更少的内存。

  • DTCoreText 允许您使用 CoreText 渲染某些 HTML 内容。

  • UIMarkupTextPrintFormatter 允许您“打印”HTML内容。它可用于获取图像。


我知道没有样例项目很难进行调试。我会尽快发布一个样例项目。 - hfossli

1
以下代码可以在webView中禁用滚动条。
webView.userInteractionEnabled = NO;

@Luke 首先,我的英语不太好。我认为问题中的代码是 webView.scrollView.userInteractionEnabled 属性。我没有测试它。但是我的代码实际上禁用了 webView 的滚动功能。我创建了一个带有许多 webView 的 scrollView,在其中无法滚动。它有效地工作。 - Steven Jiang

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