iOS UIWebView shown just part of content in UIScrollView - ios

I would like to have UIImage and UIWebView in UIScrollView so when I scroll first it would disappear image and then I would scroll with just webView. So I set it in storyboard and I added these methods to my code:
- (void)setScrollViewContentSize
{
float sizeOfContent = 0;
UIView *lLast = [_scrollView.subviews objectAtIndex:1];
NSInteger wd = lLast.frame.origin.y;
NSInteger ht = lLast.frame.size.height;
sizeOfContent = wd+ht;
_scrollView.contentSize = CGSizeMake(_scrollView.frame.size.width, sizeOfContent);
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
[webView sizeToFit];
[webView setFrame:CGRectMake(webView.frame.origin.x, webView.frame.origin.y, webView.frame.size.width, webView.frame.size.height)];
[self setScrollViewContentSize];
}
It's working just with one problem. When I scroll for a few lines I get new content of webView but after that I don't see anything. I think it has something to do with cache and that I am not scrolling in webView but with scrollView and so webView doesn't know that it should display that content. Anyone could help? Thanks

Related

UIWebView "document.height" evaluation returns wrong height on older iphones (specifically 4s and 5)

The problem is that, i have a tableview with several cells, and have a webView in one of these cells. By disabling the scroll on the webview, i should have a static web content view scrolling in the tableView, not by itself, which all works great.
In the webViewDidFinishLoad method i call
[[webView stringByEvaluatingJavaScriptFromString: #"document.height"] floatValue];
then set this value in heightForRowAtIndexPath by reloading the table. It all works great on iPhone 6 and up, but on 4s and 5, the bottom of my web content is clipped off. The returned height difference is completely random, with 724 pixel height being unclipped and fine, on other content with nearly the same returned pixel height cut off by more than 30% percent of the original.
I tried several approaches that i found here, but none of them worked.
Tried to get the max value from evaluating the offsetheight, scrollheight and other properties, but also without success.
Also tried running jquery commands on my webview, but again, without success so far.
If anyone has any experience with a problem like this, please help.
The full code snippet, where "articleViewHeight" is a constraint for the mentioned webView:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return [self getCellHeight:indexPath.row];
}
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [self getCellHeight:indexPath.row];
}
-(CGFloat)getCellHeight:(NSInteger)row{
switch (row) {
case 0:
return self.view.frame.size.height * 0.1f;
break;
case 1:
return self.view.frame.size.height * 0.375f;
break;
case 2:
return UITableViewAutomaticDimension;//self.view.frame.size.height * 0.15f;
break;
case 3:
return self.articleViewHeight;
break;
case 4:
return self.view.frame.size.height * 0.2f;
break;
default:
return UITableViewAutomaticDimension;
break;
}
}
- (void)webViewDidFinishLoad:(UIWebView * _Nonnull)webView{
CGFloat height = [self getWebViewPageHeight];
self.articleViewHeight = height;
[self.tableView reloadData];
[self removeLoader];
}
- (CGFloat) getWebViewPageHeight {
CGFloat height1 = [[self.articleView stringByEvaluatingJavaScriptFromString: #"document.height"] floatValue];
CGFloat height2 = [[self.articleView stringByEvaluatingJavaScriptFromString: #"document.body.scrollHeight"] floatValue];
return MAX(height1, height2);
}
Update: the htmlstring loading code as requested
-(void)doneLoading{
NSString *pathToFile =[[NSBundle mainBundle] pathForResource:#"news" ofType:#"css"];
NSString *fileString = [NSString stringWithContentsOfFile:pathToFile encoding:NSUTF8StringEncoding error:nil];
NSString* headerString = #"<!DOCTYPE html><html><head title='test'><style type=\"text/css\" media=\"all\">%#</style></head><body><div id='content'>%#</div></body></html>";
NSString * theString = [NSString stringWithFormat:headerString,fileString,self.htmlString];
[self.articleView loadHTMLString:theString baseURL:nil];
}
This solution works only for local html string which you can freely modify (well, you could download webpage separately into a string and inject this but then you get a load of other problems.
I've had similar problem and found following method to solve them. First of all, add this script in the <head> tag of your html.
<script type="text/javascript">
window.onload = function(){
window.location.href = "height://"+document.getElementById("content").offsetHeight;
}
</script>
This is needed because when - (void)webViewDidFinishLoad:(UIWebView *)webView; is called the content still may not have correct height. Also, put all your html content into one div with id from the script ("content" int this example).
... html header
<body>
<div id="content">
... your content
</div>
</body>
Then modify your - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType; method.
-(BOOL)webView:(UIWebView*)pWebView shouldStartLoadWithRequest:(NSURLRequest*)pRequest navigationType:(UIWebViewNavigationType)pNavigationType{
NSURL* url = pRequest.URL;
if(pNavigationType==UIWebViewNavigationTypeLinkClicked){
return ![[UIApplication sharedApplication] openURL:url];
// or do whatever you do with normal links
} else if([url.scheme isEqualToString:#"height"]){
CGFloat contentHeight = [url.host floatValue];
// do your thing with height
}
}
And viola! This made it for me. Any height error was so marginal that adding small (2px) additional bottom padding for content in CSS completely shown my content.
EDIT:
I just noticed important thing in my code. The webview have .scaleToPage flag set to NO and even more important: initial height of webview. It's set to 6k. If I change it to 0, sure enought, the content is cut after loading.
So to get correct height, the initial height of wevbiew during loading must be big enough to store whole html content without scrolling.
Since you have your webview in a cell, this won't help you. So maybe put another, hidden and big webview on the bottom of drawing stack, with same width as the one in the cell and load your conent there first, get height and then load the one in a cell.
I have had a requirement to have web view in scrollview.
The way I handled, tested without any hack. Actually this delegate method is called multiple times in a single request. Your webViewDidFinishLoad must be like below:
There is a delegate - (void)webViewDidFinishLoad:(UIWebView *)webView
I calculate web view height:-
- (void)webViewDidFinishLoad:(UIWebView *)webView{
if (webView.isLoading == NO)// as it is called multiple times so wait untill last call
{
NSDictionary* userInfo = #{#"webView": webView};
[[NSNotificationCenter defaultCenter] postNotificationName:WEB_VIEW_FINISH_LOAD object:nil userInfo:userInfo];//sending to compute content size for any view which is using this class
}
[self hideActivityOverlayAnimation:NO];
}
This is how i have computed web view height:
-(void)webViewFinishedLoad:(NSNotification*)notification{
if ([notification.name isEqualToString:WEB_VIEW_FINISH_LOAD])
{
NSDictionary* userInfo = notification.userInfo;
UIWebView* webView = (UIWebView*)userInfo[#"webView"];
[webView.scrollView setScrollEnabled:NO];// it was my requirement, dont have to do any thing with height calculation
CGFloat **height** = [[webView stringByEvaluatingJavaScriptFromString:#"document.height"] floatValue];//every time it returnes different
}
}
You can use this height to resize your cell height.
The main part which puzzle me was above. My set Up method of web view:
self.webView = [[UIWebView alloc] initWithFrame:webViewFrame];
[self.webView setDelegate:self];
self.webView.scalesPageToFit = YES;
self.webView.contentMode = UIViewContentModeScaleAspectFit;
[self.view addSubview:self.webView];
Hope it will help you !!!

Unable to fit webpage in UIWebView in ios?

I am displaying a webpage in UIWebview. My webpage looks good on the browser, but on iPhone 5s the view does not fit. It is much too large, so I want to know how I can fit the content.
I have used ScalePageToFit & sizeTofit but nothing is working.
set your web view delegate and frame.
yourwebview.frame=[[UIScreen mainScreen] bounds];
yourwebview.delegate = self;
end then use this delegate method to set height.
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
CGSize contentSize = aWebView.scrollView.contentSize;
NSLog(#"webView contentSize: %#", NSStringFromCGSize(contentSize));
yourwebview.contentsize = contentSize;
}
OR
also See my answer at How to make iOS UIWebView display a mobile website correctly?
lets try this, some web pages doesn't responds to scalesPageToFit try this not sure , just give it a try
//those web pages can handle only once the web page is loaded completely
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if ([_webView respondsToSelector:#selector(scrollView)])
{
UIScrollView *scroll = [_webView scrollView];
float zoom = ((_webView.bounds.size.width + 20 )/scroll.contentSize.width) - 0.30;
[scroll setZoomScale:zoom animated:YES];
}
}

How to size UIWebView in a UIModalPresentationFormSheet?

I tried every permutation known to mankind and I cannot get a UIWebView to size properly in a modal form view for the iPad. The web page still displays the full iPad portrait width of 768 points.
Where and how do I tell UIWebView to display width 540 points?
I thought 'scalesPageToFit' is supposed to do this but it does not work.
I tried setting the web view to the size of form view which is 540 x 576 with navigation and status bar. Height is irrelevant though.
I tried adding a UIWebView to a UIView in a storyboard with all resizing set. I then removed the UIWebView and added it programmatically.
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect aFrame = self.view.frame;
if (IS_IPAD)
{
aFrame = CGRectMake(0, 0, FORM_VIEW_WIDTH, FORM_VIEW_HEIGHT);
}
_webView = [[UIWebView alloc] initWithFrame:aFrame];
[_webView setOpaque:NO];
[_webView setDelegate:self];
[_webView setScalesPageToFit:YES];
self.view = _webView;
...
}
I also tried loading in viewDidAppear (in addition to viewDidLoad, viewWillAppear, etc.)
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[self webView] setFrame:CGRectMake(0, 0, FORM_VIEW_WIDTH, FORM_VIEW_HEIGHT)];
[[self webView] setScalesPageToFit:YES];
NSURL *webURL = [NSURL URLWithString:#"http://www.google.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:webURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0f];
[[self webView] loadRequest:request];
}
Any recommendations appreciated.
This keeps happening to me. I post a lengthy question, then two seconds later I find the answer.
Anyway, someone posted a solution to this problem here:
UIWebView -- load external website, programmatically set initial zoom scale, and allow user to zoom afterwards
However, I altered the script to set the width to the iPad width:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString* js =
#"var meta = document.createElement('meta'); "
#"meta.setAttribute( 'name', 'viewport' ); "
#"meta.setAttribute( 'content', 'width = 540px, initial-scale = 1.0, user-scalable = yes' ); "
#"document.getElementsByTagName('head')[0].appendChild(meta)";
[[self webView] stringByEvaluatingJavaScriptFromString: js];
}
Note the portion 'width = 540px, initial-scale = 1.0, user-scalable = yes'
I changed the width to the form width and scale to 1.0.
I also need to handle iPhone, and so I will make adjustments for that next. I think this fix may only be needed for the iPad form view.
UPDATE: Answer is short-lived. If I load any other page the sizing is thrown off again. Back to square one.
SOLUTION: This view will only need to access a few web pages that I developed. Therefore, I updated the few web pages that I need to access by adding the meta tag to each of them. I only need to access these pages and so this is the solution I plan to go with. This means I need to set the viewport width to 540px only for iPad somehow. I will figure that out next.
<meta name="viewport" content="width:540, initial-scale=1, maximum-scale=1">

Is there any similar solution to UIWebView?

I use a UIWebView in my app to present content, but now I can't do it anymore because I also need to use a UIScrollView and it creates conflicts related to scrolling.
Also, UIWebView is very slow.
So my question is : is there any another way to load string which contains HTML tags (strong, p, div, and etc...)?
UPDATE (improved explanation)
I have UIVIewController containing an image at the top, and under this image is a title and under the title is content (HTML string from web). The problem is that when the text is too big, the webview is scrolling, but not the whole page. I want the whole page to scroll, not just the webview.
You won't get anything faster or better than the native UIWebView. Probably you should overthink your UI/UX. What exactly do you want to achieve with a webview in a scrollview??
Perhaps attributed strings are enough for you. Look it up.
The OHAttributedLabel even parses HTML for you.
Solved.
-(void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *output = [webView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"];
int webViewHeight = [output intValue];
//NSLog(#"height: %d", webViewHeight);
if(webViewHeight > 220){
CGRect frame = articleContentWebView.frame;
frame.size.height = webViewHeight;
articleContentWebView.frame = frame;
int scrollViewheight = 416 + (webViewHeight - 220);
[articleScrollView setContentSize:CGSizeMake(320, scrollViewheight)];
}
}
In delegate method webViewDidFinishLoad I calculate height od UIWebView content and then set height of UIWebVIew and height of UIScrollView.

Text to speech and navigation

I'm using the Acapela TTS on iOS.
I have a HTML document with all the text (and markup) that I want read out.
The text is split in paragraphs and I want to be able to start the TTS at each header.
At the moment I put each paragraph in it's own UIWebView (for handling the internal markup) and add these to a UIScrollView for navigating all the elements. Each UIWebView is overloaded with a button, so when it's pressed, the connected text is read aloud.
My problem now, is that I have to place the UIWebView and Buttons using a frame (meaning a static y-position), but this entails that I have the exact height, which is my current problem.
I have tried using the solutions mentioned in this question: UIWebView height, but it still doesn't look good - either the webviews are too high or short, and I need it to be perfect, so it looks like a consistent webpage.
Does anybody know of a different way of doing this type of TTS without splitting it up in separate webviews that I have overlooked?
This is my code that place the UIWebViews:
float yOffset = 0;
UIWebView *previous = nil;
//UIWebView delegate
-(void)webViewDidFinishLoad:(UIWebView *)webView{
NSString *height = [webView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"];
if(previous!=nil){
yOffset += previous.frame.size.height;
}
CGFloat h = [height floatValue];
CGRect frame = CGRectMake(0, yOffset, scrollView.frame.size.width, h);
[webView setFrame:frame];
[webView setOpaque:NO];
[webView setBackgroundColor:[UIColor whiteColor]];
previous = webView;
[scrollView addSubview:webView];
yOffset += previous.frame.size.height;
[scrollView setContentSize:CGSizeMake(scrollView.frame.size.width, yOffset)];
}
Just an idea: you could turn the complete paragraphs into clickable links that point to some identifier of the paragraph. Then you can override the clicking event with UIWebViewDelegate and get the paragraph text with javascript. I mean something like this:
HTML:
<p id="paragraph1">First paragraph</p>
<p id="paragraph2">Second paragraph</p>
Implement shouldStartLoadWithRequest of UIWebViewDelegate:
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
NSString* link = [request.URL lastPathComponent]; // not sure
// use rangeOfString to find all
if (inType == UIWebViewNavigationTypeLinkClicked && [link compare:#"paragraph1"] == NSOrderedSame)
{
// check this
NSString* javaScript =
[NSString stringWithFormat:#"document.getElementById('%#').nodeValue", link];
NSString paragraphToRead =
[webView stringByEvaluatingJavaScriptFromString:javaScript];
// read out paragraphToRead
return NO;
}
}

Resources