I have html content which is displayed using UIWebView. User navigate pages using UIPageViewController. The problem is that the web view completes rending the content after the page is displayed. There is noticeable delay makes the performance sluggish.
- (ContentViewController *)viewControllerAtIndex:(NSUInteger)index andPageIndex: (NSUInteger)pageIndex{
if (([self.pageData count] == 0) || (index >= [self.pageData count])) {
return nil;
}
Topic * topic = (Topic *)[pageData objectAtIndex:index];
ContentViewController * contentViewController = [[ContentViewController alloc] init];
[contentViewController setCurrentTopic:topic];
[contentViewController setCurrentPageIndex:pageIndex];
return hadeethViewController;
}
The Content View Controller will not render the content unless it is really loaded by the PageViewContoller. Is there any way to enforce the view to load before the viewControllerAtIndex returns? Or is there any solution for such situation?
UIWebView can load content while not on screen. I'm guessing your issue is that your webview gets initialized only after your ContentViewController has been initialized. If you already know which HTML files will be loaded as your user pages through the content you can preload them as necessary in off-screen UIWebViews before creating the ContentViewController and add the corresponding, pre-loaded UIWebView to the content view controller.
Related
I'm using new Xcode UI Testing from XCTest Framework with the Xcode 7 GM. I've got an app with simple UIWebView (it's just a navigation controller + view controller with web view and button) and I want to check following scenario:
Web View loads page www.example.com
User taps on button
Web View loads some page with URL: www.example2.com
I want to check which page is loaded in UIWebView after pressing button. Is this possible with UI Testing right now?
Actually I'm getting web view like this:
let app:XCUIApplication = XCUIApplication()
let webViewQury:XCUIElementQuery = app.descendantsMatchingType(.WebView)
let webView = webViewQury.elementAtIndex(0)
You won't be able to tell which page is loaded, as in the actual URL that is being displayed. You can, however, check assert content is on the screen. UI Testing provides a XCUIElementQuery for links that works great with both UIWebView and WKWebView.
Keep in mind that a page doesn't load synchronously, so you will have to wait for the actual elements to appear.
let app = XCUIApplication()
app.launch()
app.buttons["Go to Google.com"].tap()
let about = self.app.staticTexts["About"]
let exists = NSPredicate(format: "exists == 1")
expectationForPredicate(exists, evaluatedWithObject: about, handler: nil)
waitForExpectationsWithTimeout(5, handler: nil)
XCTAssert(about.exists)
XCTAssert(app.staticTexts["Google Search"].exists)
app.links["I'm Feeling Lukcy"].tap()
There is also a working test host that goes along with the two links if you want to dig into the code.
If the title of the pages are different, you can check for the title of the web page.
let app = XCUIApplication()
app.launch()
//Load www.example.com
//Tap on some button
app.links["Your button"].tap()
//Wait for www.example2.com to load
let webPageTitle = app.otherElements["Example2"]
let exists = NSPredicate(format: "exists == 1")
expectationForPredicate(exists, evaluatedWithObject: webPageTitle, handler: nil)
waitForExpectationsWithTimeout(5, handler: nil)
I am updating my project from UIWebView to WKWebView. In existing UIWebView approach where UIWebView does't have any parent until it runs javascript and once it has content, it adds a parent to the webview. Content renders fine using UIWebView. I am using the same approach for WKWebView, however WKWebview stuck at loading. Is there any way we can execute javascript on wkwebview without adding parent to the webview. Another interesting thing is it works on simulator not on device. Using localHTTPServer to serve the html, css and images.
Any Suggestions or Tips to solve the above issue.
I have observed similar behavior in my app running socket.io in a headless WKWebView. In my case, the web socket would disconnect all the time and not reconnect.
It seems that since WKWebView runs javascript off-process that it will pause any javascript that is considered idle to save resources (<-IMO). Idle includes not having a parent or the app/device is inactive. So, yes, it seems like you are correct in that it needs a parent view in most cases. I was able to work around this using the following code:
WKWebViewConfiguration* webViewConfig = // set up config
// provide empty frame rect
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:webViewConfig];
// add to keyWindow to ensure it is 'active'
[UIApplication.sharedApplication.keyWindow addSubview:webView];
This approach at least ensures the javascript runs while the app is active and doesn't effect the UI. If you need to display it later you can remove the webView from the keyWindow after render and reset the frame. And, yes, I also observed that in the simulator this is not an issue (javascript ALWAYS runs, regardless of parent or app state)
Hope this helps!
The accepted solution worked for me some of the time. I tried something else which appears to work for me consistently:
self.keepWebViewActiveTimer = [NSTimer scheduledTimerWithTimeInterval:0.2
target:self
selector:#selector(_keepWKWebViewActive:)
userInfo:nil
repeats:YES];
Where _keepWKWebViewActive is:
-(void) _keepWKWebViewActive:(NSTimer*) timer{
if(self.webView) {
[self.webView evaluateJavaScript:#"1+1" completionHandler:nil];
}
}
I have a tab bar controller, one tab screen contains a web view, loading a request say google.com, when it is loading(ie before the didload delegate method call of webview), if I switch to another tab and then go back, the spinner is still running but the page is never loaded, I guess viewDidLoad is only called once, so should I put the loading code in viewDidAppear, or is there anyway to solve this?
Thanks!
I don't understand why you want to refresh the WebView everytime it appears. But use - (void)viewWillAppear:animated
Edit:
OK, since ive got more info now, i can give you more info!
In your .h:
BOOL *loaded
in your .m:
- (void)viewWillAppear:animated {
if (loaded == NO) {
//load the website
}
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[loaded setBool:YES];
}
- (IBAction)loadWebsite {
//if the user reloads or loads a new website do this:
[loaded setBool:NO];
//reload, or load the new website
}
To load, or reload your UITableView:
NSString *urlAddress = urltextfield.text;
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];
Clarification: I am setting the BOOL to YES if the View is loaded, so when the webview has finished loading and the user switches to the other tab, and back the WebView doesn't get reloaded. But if the WebView isn't fully loaded the BOOl returns NO, and the WebView will get reloaded! When the WebView gets reloaded or a new Website gets loaded im setting the BOOL to NO, and that loops over and over! Note that BOOls are NO by default.
In my windows based applicaton, after login screen and registration page I added navigation controller for next two views. After pressing button present on second navigation window,again i want normal view controller and not navigation. But Its giving me navigation window with back button which takes me to second navigation window.
Can anyone plz tell me the solution??
You have a couple choices: you can truly eliminate the Navigation Controller entirely and replace it with another UIViewController (more complicated), or you can just push a new UIViewController that will not have a navigation bar/back button, and use that as the effective "root" view controller of your application from there on out. Without the navigation bar, your view controller will look like a "normal" view controller.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.hidden = YES;
...
}
Does any one have an idea how to access the UIScroller class , which is the default subview of UIWebView ?
I want to handle the touches, zooming , panning and scrolling features inside the webview .
Thanks..
I know this thread is old but if anyone comes across it there's a new way.
As of iOS 5 UIWebView now has a property called scrollView which you can't replace but you can set the properties of it. Most people just want to disable zooming/bouncing/scrolling all together which can be done by setting the properties of the scrollView for example if webview is a UIWebView:
webview.scrollView.bounces = NO; //Disables webview from bouncing
webview.scrollView.minimumZoomScale = webview.scrollView.maximumZoomScale = 1.0; //Forces zoom to be at 1 (can be whatever you fancy) and disables zooming
webview.scrollView.bouncesZoom = NO; //Disables bouncing when zooming exceeds minimum or maximum zoom
I suppose you could set the delegate for the scrollView if you want more control, though to be on the safe side you might want to store the original delegate and call its methods appropriately in your custom delegate.
Handling the touches would be more difficult since you can't replace the scrollView to provide your own handlers. Best you could do is add some gesture recognizers as part of the UIView and try to handle them there, but I think UIWebView will still receive the events. Alternatively in iOS 5 they let you access the gesture recognizers directly on UIScrollView.
You can find this by going like this:
[webview objectAtIndex:0]
That should be where it is. If not, put this in your code somewhere and run the program to search for the index of the UIScroller, and replace the 0 above with that index:-
for (UIView *subview in [webView subviews]){
NSLog(#"subviews of webView : %#", [[subview class] description]);
}