UIWebView inside UIScrollView

My application has several UIWebView views inside a UIScrollView. Sometimes I have html content, so I load the UIWebView using the UIWebView loadHTMLString: baseURL: method. This is not a problem. I recently started loading some instances of UIWebView using url using the loadRequest: method. As soon as I started to do this, each time I scroll, I get the following error:

* Application termination due to the uncaught exception "CALayerInvalidGeometry", reason: "CALayer position contains NaN: [nan nan] '

With the following stack trace:

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:] () 

I looked at a lot of questions and answers about this and realized that the apple scares it off, but I did not see the answers that provide an alternative.

My first question is: is there an alternative way to achieve the same effect?

Below is a snippet of how I create a 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)); } } 

As you can see, I turned off scrolling and user input for UIWebView.

My second question is: why does the UIWebView (or at least one or more of its views) handle scrolling at all when I explicitly disabled this function?

My third question is: since it seems that scroll is still being processed anyway, is there any other way to intercept or disable the scroll notification that is sent to UIWebView?

As you can see, I really do not intend to let the user interact with the contents of the UIWebView - just let them view the contents.

In this case, an alternative would be to create a UIWebView outside of the UIScrollView that the user cannot see, capture its contents in an image and then display the contents in a UIImageView? If so, how would I capture the contents of a UIWebView into an image?

EDIT: I found a solution for this, which was pretty easy. Basically load your UIWebView, but don't add it as a subquery. When the UIWebView finishes loading, create the image using the code below:

 - (void)webViewDidFinishLoad:(UIWebView *)webView{ UIGraphicsBeginImageContext(self.webContent.bounds.size); [self.webContent.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [self.imageContent setImage:image]; } 

It will still be interesting for me to hear answers to questions 1 through 3. In the future, if we decide to support interactive UIWebView, this solution will not work.

Any suggestions?

+8
ios uiscrollview uiwebview
source share
5 answers

Have you tested this code on the iOS simulator or on the device itself?

I recently experienced the same crash when testing on iOS 5.1 in a simulator, but I don't experience the same crash in the iPad / iPhone 5.1.

iOS 6 works great on devices as well as on the simulator.

I believe this is due to a change in the UIWebView in iOS 6, the UIWebView has been changed to animate its contents asynchronously.

+2
source share

check the NaN values ​​when trying to set the property with:

 BOOL isNaN = isnan(your_Value); 

so that you can correctly process the values ​​as soon as you have it and you can run the code, it would be useful to find out why this happens in the first place (I would guess some dodgy calculations when getting the value that you are trying to set)

In addition, NaN is explained here: http://en.wikipedia.org/wiki/NaN

+1
source share

In fact, I can only recommend trying to write a custom "webview" class that will contain a custom NSURLConnection with NSURLRequest in the background and initiate a WebView with loadHTMLString. I have many problems using WebView in applications. So there can be no solution to calling UIWebView loadRequest.

+1
source share

It is difficult to debug this without using a sample project. Therefore, I am not sure what causes it. I would double look at your frame calculations. If your parent UIScrollView is in the interface builder, I would try disabling auto-layout to see if it matters (since contentSize works differently).

There are a few more things you could try:

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

This ensures that parent scroll scrolling will always replace web browsing. Therefore, perhaps this will prevent an error from occurring.

Depending on how you use the web view, there are several situational alternatives:

  • Call renderInContext in a UIWebView to get a screenshot and just use UIImage. After removing UIWebView, you will actually use less memory.

  • DTCoreText allows you to use CoreText to display specific HTML content.

  • UIMarkupTextPrintFormatter allows you to "print" HTML content. It can be used to get an image.

+1
source share

the code below may disable scrolling in webView.

 webView.userInteractionEnabled = NO; 
+1
source share

All Articles