UIWebView auto rotation corrupts web view content (screenshots inside) - iphone

i'm having a problem with UIWebView auto-rotating.
the web view straches alright but the content is not.
as you can see in the bottom screenshot there is a black margin, and i know it's the webview since i can see the scrollers when i scroll.
the view controller has:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
the webview has full auto resizing mask, and the view is auto-resizing subviews.
i tried a bunch of tricks from stackoverflow and google but none of them worked.
this happens only on some sites, but if i open the problematic sites in mobile safari or even ios opera browser, it rotates correctly.
EDIT: an example of a problematic site: http://m.calcalist.co.il
the webview is set in the interface builder and loading with this code:
[_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://m.calcalist.co.il"]]];
scalesPageToFit = YES; // doesn't help
Thanks!

Set the frame in willAnimateRotationToInterfaceOrientation and then set the meta tags.
Also you can set this property of UIWebView:
webView.autoResizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

You can set the web view's scalesPageToFit property to YES.
If you are generating the HTML yourself, then you can also set the viewport meta tag.
If the page has already set the viewport, you can set your viewcontroller to be the web view's delegate and change it like this:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *javaScript = #"var metatags = document.getElementsByTagName('meta'); \
for(cnt = 0; cnt < metatags.length; cnt++) { \
var element = metatags[cnt]; \
if(element.getAttribute('name') == 'viewport') { \
element.setAttribute('content','width = device-width; user-scalable = yes'); \
} \
}";
[webView stringByEvaluatingJavaScriptFromString:javaScript];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if ([self interfaceOrientation] == UIInterfaceOrientationPortrait)
[webView stringByEvaluatingJavaScriptFromString:#"document.body.style.zoom = 1.0;"];
else
[webView stringByEvaluatingJavaScriptFromString:#"document.body.style.zoom = 1.5;"];
}

Related

Change the height of the UIWebView according to the content size

I am creating a webview to display some text in my app.
CGRect frame = CGRectMake(lblContent.frame.origin.x,
lblContent.frame.origin.y,
lblContent.frame.size.width,
lblContent.frame.size.height);
NSString *htmlText = HTML_DIV_TAG;
htmlText = [htmlText stringByAppendingFormat:#"%#%#", _artistDetail.strContent, #"</div>"];
htmlText = [htmlText stringByReplacingOccurrencesOfString:#"''" withString:#"'"];
UIWebView *webView = [[UIWebView alloc]initWithFrame:frame];
[webView loadHTMLString:htmlText baseURL:nil];
webView.scrollView.bounces = NO;
[self addSubview:webView];
This is the set of codes that i put it in to my app.
But need to adjust the height of the web view according to the content size.
If you set webview.delegate = self you can add the UIWebViewDelegate protocol method webViewDidFinishLoad: and invoke a small bit of javascript to determine the height:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *output = [webview stringByEvaluatingJavaScriptFromString:#"document.body. scrollHeight;"];
NSLog(#"height: %#", output);
}
Another method would be to determine the webView's scrollView contentSize in this method, since that should fit the entire website by the time this method is called.
The only problem with this method, is that this method is called when the page finishes loading. Images are handled differently, which means that the webView might change sizes due to images that finish loading.
try -
float height= [iText sizeWithFont:[UIFont fontWithName:#"FontSpecifiedInTheHtmlText" size: -SpecifiedInHTMLText- constrainedToSize:CGSizeMake(320, 100000)lineBreakMode:UILineBreakModeWordWrap].height;
after u get the height of the content text, u can set the frame/bounds of the WebView.
You may want this:
[webView.scrollView setContentInset:UIEdgeInsetsMake(0, 0, 20, 0)];
UIWebview is scrollable. So when you open a page in UIWebview u need not adjust the height according to the content of the page. You can see all the content by scrolling the UIWebView. You should check that user interaction is enabled for your webview.

UIWEBVIEW +contents fit in frame of webview

I am using UIwebview in my project.Where the the cotent in the webview is been filled from html data By doing below code like this:
[webView loadHTMLString:[NSString stringWithFormat:#"<html><body><font face=\"Arial\" size=\"3\"</font>%#</body></html>",[[[dict_Response objectForKey:#"objects"]objectAtIndex:0]objectForKey:#"detaildescription"]] baseURL:[NSURL URLWithString:#"http://newsletter.nobelbiocare.com/"]];
Now i am setting the frame of webview:-
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(appDel.ori_appDel == UIInterfaceOrientationPortraitUpsideDown || appDel.ori_appDel == UIInterfaceOrientationPortrait)
{
webView.frame=CGRectMake(30,150,710,450);
}else{
webView.frame=CGRectMake(30,150,930,450);
}
return yes;
}
Now the thing happen is in Landscape mode the content is showing in proper way.But when i move to portrait mode it automatically shows horizontal scrolling.I dont want to scroll the webview in horizontal mode..
Please help me..How to solve this.
I had used sizetofit and autoresizing|autofixing.
But then also it is not solving Please help me..
#shweta
try to update your webview in webViewDidFinishLoad: this will help you. and try to set the size in html rather than web view frame.
- (void)webViewDidFinishLoad:(UIWebView *)webview {
CGRect oldBounds = [[self webview] bounds];
//in the document you can use your string ... ans set the height
CGFloat height = [[webview stringByEvaluatingJavaScriptFromString:#"document.height"] floatValue];
[webview setBounds:CGRectMake(oldBounds.origin.x, oldBounds.origin.y, oldBounds.size.width, height)];
}
the main concern is the method .
[webview stringByEvaluatingJavaScriptFromString:#"document.height"]
by using javascript.
Instead of
sizetofit and autoresizing|autofixing
Write
webview.scalePageToFit=TRUE
Use this:
[webView loadHTMLString:[NSString stringWithFormat:#"<html><div style='font-family: arial,helvetica;font-size: 14px;'>%#</div></html>",[[[dict_Response objectForKey:#"objects"]objectAtIndex:0]objectForKey:#"detaildescription"]] baseURL:[NSURL URLWithString:#"http://newsletter.nobelbiocare.com/"]];
Try these
1. Put format specifier between body tag as </font>%#</body></html>.
2. Try reloading web view in this
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
//Reload your web view here
}

UIWebView disable zooming when scalesPageToFit is ON

Is there any way to disable zooming when Scales page to Fit is ON ??
This works for me:
UIScrollView *scrollView = [webView.subviews objectAtIndex:0];
scrollView.delegate = self;//self must be UIScrollViewDelegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return nil;
}
UPDATE: For iOS 5 or higher get scrollView like this:
webview.scrollView.delegate = self;
Instead of using
UIScrollView *scrollView = [webView.subviews objectAtIndex:0];
scrollView.delegate = self;//self must be UIScrollViewDelegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return nil;
}
You can use this:
webview.scrollView.delegate = self;
-(UIView*)viewForZoomingInScrollView:(UIScrollView*)scrollView {
return nil;
}
Second option is better and full-proof. First logic could fail in future SDKs.
There's property called scrollView in UIWebView. Through it you can define this.
To be more specific it should look like this:
myWebView.scrollView.minimumZoomScale = 1.0;
myWebView.scrollView.maximumZoomScale = 1.0;
Edit:
Implement delegate method
- (void)webViewDidFinishLoad:(UIWebView *)webView
For your web view and in it add folowing code:
[webView stringByEvaluatingJavaScriptFromString: #"$('body').bind('touchmove', function(event) { event.preventDefault() });"];
The problem is this also disable the scroll, because it disable the move of touch.
If you want to keep the scroll you have to write a java script that will overwrite the viewport meta tag with:
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
From the Apple Documentation:
scalesPageToFit
A Boolean value determining whether the webpage scales to fit the view
and the user can change the scale.
#property(nonatomic) BOOL scalesPageToFit
Discussion
If YES, the webpage is scaled to fit and the user can zoom in and zoom
out. If NO, user zooming is disabled. The default value is NO.
So if you want to change that behavior, you will probably have to subclass UIWebView.
so it works at me:
NSString *fullURL = #"http://google.com";
NSURL *url = [NSURL URLWithString:fullURL];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
_webView.scrollView.scrollEnabled = TRUE;
_webView.contentMode = UIViewContentModeScaleAspectFit;
_webView.scalesPageToFit = FALSE;
[_webView loadRequest:requestObj];

UIWebView does not scale content to fit

I have a webview which is the top window in the hierarchy and has been declared as shown below. However, it does not scale pages to fit. Pages are top left aligned, but are not scaled, despite the scalesPageToFit property being set to YES. Any help would be greatly appreciated.
webLookupView = [[UIWebView alloc] initWithFrame:CGRectMake(16, 63, 289, 327)];
webLookupView.backgroundColor = [UIColor lightGrayColor];
webLookupView.dataDetectorTypes = UIDataDetectorTypeAll;
webLookupView.scalesPageToFit = YES;
iOS5 gives a better solution
call this from webViewDidFinishLoad
- (void)zoomToFit
{
if ([theWebView respondsToSelector:#selector(scrollView)])
{
UIScrollView *scrollView = [theWebView scrollView];
float zoom = theWebView.bounds.size.width / scrollView.contentSize.width;
scrollView.minimumZoomScale = zoom;
[scrollView setZoomScale:zoom animated:YES];
}
}
I have subsequently discovered that some web pages are correctly scaled, but some are not. For web pages which are not properly scaled, javascript can be used to control zooming as follows:
NSString *jsCommand = [NSString stringWithFormat:#"document.body.style.zoom = 1.5;"];
[webLookupView stringByEvaluatingJavaScriptFromString:jsCommand];
You can use the below code:
self.webView.scalesPageToFit = YES;
self.webView.contentMode = UIViewContentModeScaleAspectFit;
in - (void)webViewDidFinishLoad:(UIWebView *)webView method
or viewDidLoad
If you have access to the html you are loading you can chuck the following meta tag in the header :
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
in Swift2
self.webView.scalesPageToFit = true
self.webView.contentMode = UIViewContentMode.ScaleAspectFit
My solution in swift:
"Scales pages to fit" on webView needs to be checked in interface builder.
Use UIWebViewDelegate.
func webViewDidFinishLoad(webView: UIWebView) {
let zoom = webView.bounds.size.width / webView.scrollView.contentSize.width
webView.scrollView.setZoomScale(zoom, animated: true)
}
As mprivate mentions here you can update the zoom level of the UIWebView.
- (void)webViewDidFinishLoad:(UIWebView *)theWebView {
CGSize contentSize = theWebView.scrollView.contentSize;
CGSize viewSize = theWebView.bounds.size;
float rw = viewSize.width / contentSize.width;
theWebView.scrollView.minimumZoomScale = rw;
theWebView.scrollView.maximumZoomScale = rw;
theWebView.scrollView.zoomScale = rw;
}
Another way of achieving this would be injecting js code on the webViewDidFinishLoad as RunLoop says.
- (void)webViewDidFinishLoad:(UIWebView *)webView {
CGFloat scale = 0.8; // the scale factor that works for you
NSString *js = [NSString stringWithFormat:#"document.body.style.zoom = %f;",scale];
[webView stringByEvaluatingJavaScriptFromString:js];
}
Anybody looking for WKWebView answer, please try the below code:
extension YourViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"
webView.evaluateJavaScript(jscript)
}
}
Remember to set the navigationDelegate of the Webview.
For Swift 3, using RunLoop's effective answer:
self.webView.stringByEvaluatingJavaScript(from: "document.body.style.zoom = 1.5;")
In xCode 8.3.3, go to the storyboard of the view/scene where the web view is located and check Scale Page to Fit in the attributes inspector section . Also select Scale to Fill as the content mode.
Try this in your ViewController's viewDidLoad
[self.myWebView setFrame:CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
self.view.frame.size.height)];
I also have the webview set to "scalePageToFit" and viewmode set to "Aspect Fit" in my Storyboard.
There is "Scale To Fit" option in interface builder, so it should be something programatic to do the same.

iPhone SDK - UIWebView has a grey box over it

Sometimes, my UIWebView will have a grey box over part or all of the content. I can't make heads or tails of why it's happening. It happens regularly for certain content.
Thanks!
--Update--
It seems to occur when the webview is not immediately viewable on the screen -- ie i've got a scrollview, and the webview is below the fold.
--Update #2--
When I bring the content above the fold, it loads fine most of the time. There are still instances when the grey box is still showing up. The weird part is if i double-tap it, it finishes loading the content just fine. bizarre
--Update #3--
Okay, so it seems to be that if my uiwebview has a height greater than 1000px, a grey box appears on the rest of the content below 1000px. A double-tap reveals the actual content.
All UIViews have a size limit of 1024x1024 pixels. This is stated at the end of the Overview section of the UIView documentation.
If your web view must have more than 1024px of content, you will have to take it out of the parent scroll view and let it manage scrolling on its own.
Nudging the UIScrollView in the UIWebView it fixes this for me:
[UIScrollView *webScroller= [[webView subviews] lastObject];
[webScroller setContentOffset:CGPointMake(0,1) animated:NO];
[webScroller setContentOffset:CGPointMake(0,0) animated:NO];
I have been dealing with this glitch as well, and have opened a bug report at apple.
I would have commented above, but I don't have the 50 rep yet.
For anyone else encountering this glitch, send them a report, I included a full project demonstrating it, with a few screenshots from another app I am working on.
The more bug reports they get on a topic, the more likely they are to address it, apparently.
https://bugreport.apple.com/
I've got the same problem. I put a UIWebView inside a big TableViewCell (>1024px) and when I scroll to the bottom of the cell, there is this grey box.
But, if I put a UILabel (also with a big size > 1024px), there is no grey box. So I think this has nothing to do with a max height of a UIView (BTW I can't find anything about this so called 1024 max height). I think it's more a UIWebView issue.
The solution for me is to reload the content of the webview when the grey box appears. Actually, I just have a HTMLString to load so I call [webview loadHTMLstring:] again, and the grey box disappear.
Hope that will help
I found a very intersting post about that, it solved the problem for me :
link ttp://pinchzoom.com/blog/items/view/1386/one-of-the-problems-with-the-uikit-at-the-moment-is-an-issue-embedding-a-uiwebview-within-a-table
Hope that helps
I've used stringByEvaluatingJavaScriptFromString plus moving UIWebView origin.
Design overview: I had a set of controls(UIImage in this example) above(I mean frame.origin.y) UIWebView. So, layout was:
UIView
UIScrollView
UIImageView
UIWebView
Since UIWebView doesn't support scrolling in such hierarchy I've rearrange it like:
UIView
UIScrollView
UIImageView
UIWebView
My view controller is delegate for UIWebViewDelegate and UIScrollViewDelegate.
Then,
- (void)viewDidLoad
{
// set delegates
self.scrollView.delegate = self;
self.webView.delegate = self;
// store original UIWebView position in ivar
webViewPosY = self.webView.frame.origin.y;
// load html into UIWebView
[self.webView loadHTMLString:someHTML baseURL:nil];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// get UIWebView size and store in ivar
webSize = [self.webView sizeThatFits:CGSizeMake(1.0,1.0)];
// set proper content height for UIScrollView
CGSize contentSize = self.scrollView.contentSize;
contentSize.height = webViewPosY + webSize.height;
self.scrollView.contentSize = contentSize;
// set UIWebView's frame height same as UIScrollView has
CGRect wf = self.webView.frame;
wf.size.height = self.scrollView.frame.size.height;
self.webView.frame = wf;
}
// scrolling logic:
// 1. if origin of UIWebView > 0 then move UIWebView itself
// 2. if origin of UIWebView == 0 then scroll with javascript
// 3. if origin is 0 and whole html is scrolled then move UIWebView again(this happens to support scroll "bouncing", or if you have some views below UIWebView
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat scrollPosY = self.scrollView.contentOffset.y;
// (1) and (2) ifs
// how much to move UIWebView
CGFloat scrollOriginY = (scrollPosY >= webViewPosY) ? webViewPosY : scrollPosY;
// how much to scroll via JS
CGFloat scrollJSY = scrollPosY - scrollOriginY;
// (3) if
if ( scrollPosY > (webSize.height - scrollViewSize.height + webViewPosY ) )
scrollOriginY += scrollPosY - (webSize.height - scrollViewSize.height + webViewPosY);
// scroll with JS
[self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"document.body.scrollTop = %f;", scrollJSY]];
// move UIWebView itself
CGRect wf = self.webView.frame;
wf.origin.y = webViewPosY - scrollOriginY;
self.webView.frame = wf;
}
This works just fine for me.
I ran into the same issue when dynamically resizing a UIWebView. Here's what worked for me:
#define LAYER_FOR(ui) [(ui) layer]
#define FRAME_FOR(ui) [LAYER_FOR((ui)) frame]
#define SET_FRAME_FOR(ui, frame) [LAYER_FOR((ui)) setFrame: (frame)]
+ (void) setHeightTo: (CGFloat *) height_ptr forView: (UIView *) a_view {
CGFloat height = *height_ptr;
CGRect existing_frame = [[a_view layer] frame];
existing_frame.size.height = height;
// need to reassign the same frame !?
NSLog(#"setting text view: %# to height: %f", a_view, (float) height);
SET_FRAME_FOR(a_view, existing_frame);
}
+ (void) resizeWebView: (UIWebView *) webView {
NSString *js = #" \
var __html_element = document.getElementsByTagName('html')[0]; \
var __height_string = document.defaultView.getComputedStyle(__html_element, null).getPropertyValue('height'); \
__height_string.replace('px', ''); \
";
NSString *heightString = [webView stringByEvaluatingJavaScriptFromString: js];
float height = [heightString floatValue];
if (height != UI_VIEW_HEIGHT(webView)) {
[self setHeightTo: &height forView: webView];
// resize scrollView inside webview to the same height
UIScrollView *webScroller = [[webView subviews] lastObject];
[self setHeightTo: &height forView: webScroller];
}
}
I called this code from webview's delegate 'webViewDidFinishLoad:' method.
Basically, the trick is to resize the webScroller inside webview.
Thanks to Padraig for the suggestion to nudge the webview's subview (the scrollview).