I have a screen that shows a web view. However, I allow people to cycle through different web views by updating an object. When I load the first page, the web view loads fine. However, when I try to update the page from the new object in viewwillappear, while other elements such as a title that goes above the webview load fine, the web view does not refresh.
//in viewWillAppear
self.title = self.file.imageDescript;//The title loads fine
NSString *urlBase = #"https://www.~com/images/";
NSString * imagename = self.file.imagename;
NSString *url = [NSString stringWithFormat:#"%#%#",urlBase,imagename];
NSURL *realUrl = [NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:realUrl];
[webView loadRequest:request];
I have tried various versions of setNeedsDisplay and also applied these to subviews of the web view without success as in this method:
- (void) forceRedrawInWebView:(UIWebView*)webView {
NSArray *views = webView.scrollView.subviews;
for(int i = 0; i<views.count; i++){
UIView *view = views[i];
//if([NSStringFromClass([view class]) isEqualToString:#"UIWebBrowserView"]){
[view setNeedsDisplayInRect:webView.bounds]; // Webkit Repaint, usually fast
[view setNeedsLayout]; // Webkit Relayout (slower than repaint)
// Causes redraw & relayout of *entire* UIWebView, onscreen and off, usually intensive
[view setNeedsDisplay];
[view setNeedsLayout];
// break; // glass in case of if statement (thanks Jake)
//}
}
}
I have read in one SO answer that since IOS8.2, refresh of UIWebView no longer works (as WKWebView) has replaced it. I would switch to WKWebView except that it is not supported in storyboards, apparently, and I have a bunch of stuff going on in the storyboard.
Note: this has nothing to do with refreshing the same web url because content has changed on a server. It has to do with loading an entirely different web url in the UIWebView
Can anyone suggest way to fix this?
Related
I have a master table and detail view controller. The detail VC shows URLs through a web view.
If using the built in navigation of the master/detail setup, if I go back and then press a different table cell, the detail view will update the web view. This is true whether I use a UIWebView or a WKWebView.
However, within the detail view, without having to go back to the table, I want to give the user the option to view more than one url through the same web view. I am trying to do this in viewwillappear by changing the url for the request. However, the UIWebView (or alternatively WKWebView) continue to show the same url. I can't seem to get rid of the first url.
I've tried all kinds of ways to close or stop the existing web view, clear the cache, delete cookies etc. before reloading the new one but still see the same url. Would appreciate any suggestions. Here is my code and some of the things I've tried that don't work:
-(void) changeURL: (NSNumber*)param {
NSURL *testurl1=[NSURL URLWithString:#"http://www.apple.com"];
NSURL *testurl2 =[NSURL URLWithString:#"http://www.google.com"];
//if param is 1 {
_urlToLoad = testurl1;}
else {
_urlToLoad = testurl2;}
}
Edit: Method below is updateInterface, not viewWillAppear
-(void) updateInterface {
UIWebView *webView;
NSURLRequest *request=[NSURLRequest requestWithURL:_urlToLoad];
webView = nil;//This blocks the web view from loading at all for some reason I can't understand. Setting wkWebView to nil does not block loading.
[webView stopLoading];//no effect
[webView loadRequest:request];
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSString *myDomain = #"www.google.com";
for(NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
if([[cookie domain] isEqualToString:myDomain]) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
}
}
//wkwebview version
WKWebView *wkwebView;
WKWebViewConfiguration *wkConfig = [[WKWebViewConfiguration alloc] init];
wkwebView = nil;
wkwebView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:wkConfig];
wkwebView.navigationDelegate = self;
[wkwebView loadRequest:request];
[webView addSubview:wkwebView];
CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
webFrame.origin.y = 100.0; // statusbar
webFrame.origin.y -= 100.0; // statusbar 20 px cut from y of frame
webView = [[UIWebView alloc] initWithFrame:webFrame];
}
The UIViewController method "viewWillAppear" has the following signature in Objective-C:
- (void)viewWillAppear:(BOOL)animated
, you implemented it without any arguments.
The result is that, instead of being taken as an override of the original method defined in the superclass UIViewController, it is treated as a brand new, custom method introduced by your subclass; and unless you call it explicitly somewhere, it will never execute.
Source: SDK Reference
This is an issue with iOS9 and later.
On the load of application I select a word in UIWebview but theres no editview popup showing copy, share, define etc options on first tap.
From next selection after the tap it works fine.
even the -(BOOL)canPerformAction:(SEL)action withSender:(id)sender delegate returns NO for all options on first tap and select
Also when you select a word and scroll it up off the screen and try to select other word. the view scrolls up/down on its own and a worng word will be selected(View displaces itself by an offset of the amount the selected word is scrolled off the screen).
Pulling my hair to get this fixed. Any help would be appreciated
its simple code
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view becomeFirstResponder];
NSString *urlAddress = #"https://en.wikipedia.org/wiki/Main_Page";
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[_myWebView loadRequest:requestObj];
}
UIWebview has many bugs and is not memory efficient .
Replaced UIWebview with WKWebView on apple's recommendation and it fixed all the bugs.
In my app, I am trying to make a splash image appear as my UIWebView loads so it is not just a blank screen. However my webViewDidFinishLoad method will not work. This means that the splash image appears but does not disappear from the screen once the UIWebView has loaded.
My code for the method is:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSLog(#"content loading finished");
[loadingImageView removeFromSuperview];
}
Any help on why the method will not work would be appreciated greatly.
My .h:
#interface ViewController : UIViewController
-(IBAction)makePhoneCall:(id)sender;
#property (nonatomic, strong) IBOutlet UIWebView *webView;
#property(nonatomic, strong) UIImageView *loadingImageView;
#end
My ViewDidLoad and webViewDidFinishLoading:
- (void)viewDidLoad {
UIWebView *mWebView = [[UIWebView alloc] init];
mWebView.delegate = self;
mWebView.scalesPageToFit = YES;
[super viewDidLoad];
}
//**************** Set website URL for UIWebView
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.sleafordpizza.com/food"]]];
//**************** Add Static loading image to prevent white "flash" ****************/
UIImage *loadingImage = [UIImage imageNamed:#"LittleItalyLogo.png"];
loadingImageView = [[UIImageView alloc] initWithImage:loadingImage];
loadingImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"LittleItalyLogo.png"],
nil];
[self.view addSubview:loadingImageView];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSLog(#"content loading finished");
// Remove loading image from view
[loadingImageView removeFromSuperview];
}
Hi probably you do not set proper delegate.
This is small code tip for you.
-(void)viewDidLoad {
mWebView = [[UIWebView alloc] init];
mWebView.delegate = self;
mWebView.scalesPageToFit = YES;
}
-(void)webViewDidFinishLoad:(UIWebView *)webView {
[loadingImageView removeFromSuperview];
NSLog(#"finish");
}
In you're .h file add.
#interface MyView: UIViewController <UIWebViewDelegate> {
UIWebView *webView;
}
Code fixes.
For .h file
#interface ViewController : UIViewController<UIWebViewDelegate>
-(IBAction)makePhoneCall:(id)sender;
#property (nonatomic, strong) IBOutlet UIWebView *webView;
#property(nonatomic, strong) UIImageView *loadingImageView;
#end
For .m file
- (void)viewDidLoad
{
[super viewDidLoad];
webView.delegate = self;
//**************** Set website URL for UIWebView
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.sleafordpizza.com/food"]]];
//**************** Add Static loading image to prevent white "flash" ****************/
UIImage *loadingImage = [UIImage imageNamed:#"LittleItalyLogo.png"];
loadingImageView = [[UIImageView alloc] initWithImage:loadingImage];
loadingImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"LittleItalyLogo.png"],
nil];
[self.view addSubview:loadingImageView];
}
At certain times, this delegate method actually never gets fired. I have had severe problems with the same thing in some of my projects.
At one occasion, I actually had to solve it with a timer, checking the state of the web view every second or so to see if I could proceed.
In that particular case, I just needed a certain element to be present. Still, the view did not trigger the finish loading event, due to external script errors being injected.
So, I just started a trigger when the web view begun loading, then called a method every now and then to see if the web view contained the element in question.
- (void)methodCalledByTimer {
if (<I still do not have what I need>) {
//The web view has not yet finished loading; keep checking
} else {
//The web view has finished loading; stop the timer, hide spinners and proceed
}
}
You could also check if the web view is actually loading, if that is absolutely necessary:
- (void)methodCalledByTimer {
if (self.webView.isLoading) {
//The web view has not yet finished loading; keep checking
} else {
//The web view has finished loading; stop the timer, hide spinners and proceed
}
}
Then, naturally, I'd check for the finishedLoading event as well, just to be sure. Remember to also implement the webView:didFailLoadWithError: method as well.
When waiting for a web page to finish loading, there are some things to keep in mind.
For instance, do you really need it to stop loading, or is there anything else you can do? In my case, I needed an element. Being able to properly execute a script is another thing that may be required.
Second, is the loading page using any external resources? I once had external script errors causing the webViewDidFinishLoad: method to not being called at all. If I removed the external scripts, it worked.
Third, if the page is using external resources, you are exposed not only to the loading capacity of your own resources, but that of the external resources as well. Tracking scripts, ads etc...if one resource provider is delivering content sloooowly (or not at all), you could page could be stuck in loading state forever.
So, I'd go with checking for something else. :)
I see you aren't handling errors. If there is an error, all subsequent delegate calls will not happen. I was surprised to find that this is true when the webview uses a plugin too. It calls this error method telling you that the webview handed off to the delegate, in my case the movie player.
implement this and see if that is it.
-(void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
if (error.code == 204) {
//request was handled by a plugin instead of by the webview directly
...
}
else
{
NSLog(#"didFailLoadWithError. ERROR: %#", error);
}
}
I was able to do all the remaining loading work in this method instead of the webviewdidfinishLoad
I'd like to have my UIWebView respond to touch event from user, and also let views from behind respond to touch. Is it possible?
basically, i'd like to have my UIWebView interact with a touch but not "swallowing" it, and let it go through for another lower view too.
The short answer, I believe, is no.
The best that you could do is to capture the touches in the UIWebView using one or more UIGestureRecognizers and then manually manipulate or trigger actions in the lower UIViews.
This is possible if an only if your webview is made by you. It will be done in PHP code for that site ie. when you tap on any button or any event is detected on your webview, then a parameter can be passed by PHP code from server in form of hidden field. You can recieve this by following code:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
//NSString *html = [webView stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
//NSLog(#"%#",html);
NSString *hdnPaymentStatusId = [webView stringByEvaluatingJavaScriptFromString: #"document.getElementById('yourParametrer1').value"];
NSLog(#"value%#",hdnPaymentStatusId);
if ([hdnPaymentStatusId integerValue] == 1)
{
DWMyOrdersViewController *myOrderVC = [self.storyboard instantiateViewControllerWithIdentifier:#"DWMyOrdersViewController"];
[self.navigationController pushViewController:myOrderVC animated:YES];
}
NSString *hdnCancelStatusId = [webView stringByEvaluatingJavaScriptFromString: #"document.getElementById('yourParametrer2').value"];
NSLog(#"value%#",hdnCancelStatusId);
if ([hdnCancelStatusId integerValue] == 1)
{
[self dismissViewControllerAnimated:YES completion:nil];
}
}
Well, after reading a bunch of SO posts on this issue, I still can't fix problems with my activity indicator. This indicator is in a view in a tab under the control of its own view controller. It has a view with a UIWebView which loads a local html page just fine. The view is loaded with initWithNibName and then awakeFromNib. Here's the part I think is relevant:
#implementation HelpViewController
#synthesize webView = _webView;
#synthesize back = _back;
#synthesize forward = _forward;
#synthesize aI = _aI;
- (void) viewDidLoad {
_aI = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[_aI stopAnimating];
// Now add the web view
NSString *filePath = [[NSBundle mainBundle]
pathForResource:#"Help"
ofType:#"html"];
[self.view addSubview:_webView];
_webView.delegate = self;
NSURL* fileURL = [NSURL fileURLWithPath:filePath];
NSURLRequest *request = [NSURLRequest requestWithURL:fileURL];
[_webView loadRequest:request];
[super viewDidLoad];
}
-(void) webViewDidStartLoad:(UIWebView *)webView {
[_aI startAnimating];
_back.enabled = NO;
_forward.enabled = NO;
}
-(void) webViewDidFinishLoad:(UIWebView *)webView {
[_aI stopAnimating];
if (webView.canGoBack) {
_back.enabled = YES;
_back.highlighted = YES;
}
if (webView.canGoForward) {
_forward.enabled = YES;
_forward.highlighted = YES;
}
}
The navigation buttons work fine. The activity indicator was placed in the nib, but in the main view, not on/over/under the webView. In the attributes, I have Hides When Stopped checked. If I check Animating the indicator is always visible and animated, no matter how I navigate through the UIWebView.. If I uncheck Animating, Hidden is automatically checked for me. In this case, the indicator never shows up. So it's either always on or always off.
I've read quite a bit about cases where you need to have the indicator on a different thread. I'm not sure, but I don't think that applies here (I load a local html page but allow users to navigate off and then back to the local page). But, I seem to have some disconnect; perhaps it is the fact that the indicator is in the main view but the pages are in the webView? Or I'm not calling things in the right methods. Or who knows... Thanks for any help!
You overwrite _aI in your viewDidLoad and never place it in your view hierarchy, so the object you are sending the messages to is never visible and the activity indicator placed in interface build will never change its state, so thats why its either always animating or hidden.