I have a tabbed app which loads separate internal file WKwebviews. I now need to have the WKwebview refresh when a tab is selected.
I think I need to add the required code in the viewWillAppear, but on trying to have some code on this method nothing works.
Does anyone have any suggestions as to how I can achieve this
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
webView.configuration.userContentController.add(self, name: "jsHandler")
let bundleURL = Bundle.main.resourceURL!.absoluteURL
let html = bundleURL.appendingPathComponent("main/index.html") //Loads internal HTML files
webView.loadFileURL(html, allowingReadAccessTo:bundleURL)
webView!.uiDelegate = self
webView.allowsBackForwardNavigationGestures = true //Allows 'safari' style gestures swipe back etc
}
override func viewWillAppear(_ animated: Bool) {
//Nothing
}
Update:
To resolve this, I added the above code into the viewDidAppear method rather than the viewDidLoad. This has resolved the problem.
The JS message handler still needs to be in the viewDidLoad.
Example:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
webView.configuration.userContentController.add(self, name: "jsHandler")
}
override func viewDidAppear(_ animated: Bool) {
//webView.configuration.userContentController.add(self, name: "jsHandler")
let bundleURL = Bundle.main.resourceURL!.absoluteURL
let html = bundleURL.appendingPathComponent("index.html") //Loads internal HTML files
webView.loadFileURL(html, allowingReadAccessTo:bundleURL)
webView!.uiDelegate = self
webView.allowsBackForwardNavigationGestures = true //Allows 'safari' style gestures swipe back etc
}
Try something like this on each tab action:
func reloadTabAction() {
if let url = webView.url {
webView.reload()
} else {
webView.load(URLRequest(url: originalURL))
}
}
We have reload property for WKWebView. So you can directly call the method.
You can call the method while tapped the tabView
Try the below code,
webView.reload()
Related
I have a UITabBar containing 5 tabs. I disabled one of the tabs like this:
tabBar.items?[3].isEnabled = false
To enable it again, I am using the following code:
tabBar.items?[3].isEnabled = true
The problem is that it doesn't actually get enabled again. I also tried to place the above code inside viewWillAppear and viewDidAppear, but the tab stays disabled.
Here's the full code:
import UIKit
class MainTabViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
tabBar.items?[0].title = NSLocalizedString("tab1", comment: "-")
tabBar.items?[1].title = NSLocalizedString("tab2", comment: "-")
tabBar.items?[2].title = NSLocalizedString("tab3", comment: "-")
tabBar.items?[3].title = NSLocalizedString("tab4", comment: "-")
tabBar.items?[4].title = NSLocalizedString("tab5", comment: "-")
self.tabBar.items?[3].isEnabled = true
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
}
It should be the tabBar property of the UITabBarController.
self.tabBarController?.tabBar.items?[3].isEnabled = false
If you call it from inside the custom UITabBarController subclass:
self.tabBar.items?[3].isEnabled = false
Make sure viewWillAppear and viewDidAppear of the custom UITabBarController subclass are called only once, unlike the methods in every tab, since they are called every time the tab is selected.
The below code seems to work fine:
self.tabBar.items?[3].isEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.tabBar.items?[3].isEnabled = true
}
In my code, when a view disappears, a specific action occurs. I am doing it through the viewDidDisappear() function.
I have a specific button that when is pressed it goes to another view. I was wondering in what I way I could tell ONLY the function caused by a specific button to skip the viewDidDisappear().
I perfectly know I can add a sort of 'if' statement in the viewDidDisappear() but I was wondering if there was a more efficient method.
viewDidDisappear() is a UIViewController's lifecycle callback method that's called by the environment - as far as I know there is no way to disable its calling. And I don't think there should be - as I mentioned, it is a part of UIViewController's lifecycle, not calling it would break the contract - see its documentation.
Therefore you have to (and you should) achieve what you want by using if statement.
Do something like this:
fileprivate var skipDisappearingAnimation = false
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
prepareInterfaceForDisappearing()
}
fileprivate func prepareInterfaceForDisappearing() {
guard !skipDisappearingAnimation else {
// reset each time
skipDisappearingAnimation = false
return
}
// do the stuff you normally need
}
#objc fileprivate func buttonPressed(_ sender: UIButton) {
skipDisappearingAnimation = true
// navigate forward
}
It cannot be done; you must handle the case manually with if, something like:
var shouldSkip: Bool = false
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if !shouldSkip {
// your code goes here
}
shouldSkip = false // don't forget to set should skip to false again
}
#IBAction func buttonDidTap(_ sender: Any) {
shouldSkip = true // this will avoid run your code
// your code here
}
I've a UITabBarController with two tabs. In each tab there is a table, and in the viewWillAppear I load the data and reload the table:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tableView.delegate = self
tableView.dataSource = self
loadTasks()
}
func loadTasks(){
let url = Api.GET_TASK_USER_MONTH
Task.getTasks(url) { tasks in
if !tasks.isEmpty {
for index in 0...tasks.count-1 {
self.tasks.append(tasks[index])
}
}
self.tableView.reloadData()
}
}
But every time I switch between the tables the data displayed is wrong. It fires displays the second's tab data, then it displays OK the first one and then it displays the one's data all the time in the two views.
Any ideas?
UPDATED: My loadTasks() method.
Normally viewWillAppear should be called if you "enter" the tab.
It might be the case that the ViewController gets not deinitialized => the ViewController is still there and therefore viewWillAppear will not be called.
You might need to use a weak self in loadTasks:
func loadTasks(){
let url = Api.GET_TASK_USER_MONTH
Task.getTasks(url) { [weak self] tasks in
if !tasks.isEmpty {
for index in 0...tasks.count-1 {
self?.tasks.append(tasks[index])
}
}
self?.tableView.reloadData()
}
}
I'm loading html string by WebView in my app. Current issue is that when my WebView load content that contains another link and when user click on that link, new view is not opening in my app - it opens in default browser. How can I open that link in WebView? Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
self.edgesForExtendedLayout = UIRectEdge.None
SVProgressHUD.show()
//EZLoadingActivity.show("أرجو الإنتظار", disableUI: true)
self.automaticallyAdjustsScrollViewInsets = false
self.navigationController!.navigationBar.tintColor = UIColor.whiteColor()
self.navigationController!.navigationBar.barStyle = UIBarStyle.Black
self.navigationController!.navigationBar.tintColor = UIColor.whiteColor()
let logo = UIImage(named: "toolbar_icon3")
let imageView = UIImageView(image:logo)
self.navigationItem.titleView = imageView
myweb.loadHTMLString(webviewurl, baseURL: nil)
}
Android allows to do it with:
public boolean shouldOverrideUrlLoading(WebView view, String url)
But on iOS how can we do this?
You could try creating a url request for you UIWebView.
yourWebView.loadRequest(NSURLRequest(URL: NSURL(string: "google.ca")!))
If you would like to do something while the web view is opening, you could use the UIWebViewDelegate statement.
In your class:
class ViewController: UIViewController, UIWebViewDelegate {
Then,
yourWebView.delegate = self
And finally, you can use:
func webViewDidStartLoad(webView: UIWebView) {
//do something while the web view is loading!
}
For more information on UIWebViewDelegate, visit Apple's Documentation.
I'm have a WebView:
func loadPage() {
let request = NSURLRequest (URL: url!)
myBrowser.loadRequest(request)
}
Which load RTF document from this URL:
var url: NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Chapter1", ofType: "rtf")!)!
How can I save last scroll position to NSUserDefaults, to get it then (if user pause reading and resume it).
Or maybe other type or method to make bookmark in this case.
Note: Ive been trying this:
var myBookmark: CGPoint = CGPointMake(0, 0)
override func viewWillDisappear(animated: Bool) {
myBookmark = myBrowser.scrollView.contentOffset
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
myBrowser.scrollView.delegate = self
myBrowser.scrollView.setContentOffset(myBookmark, animated: false)
}
But it's not take any effect.
UPD1: translate my VAR name.
To save and retrieve your scrollview offset from NSUserDefaults, set your UIWebView's delegate and try this:
var viewLaidoutSubviews = false // <-- variable to prevent the viewDidLayoutSubviews code from happening more than once
// Save your content offset when the view disappears
override func viewWillDisappear(animated: Bool) {
var userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setValue(NSStringFromCGPoint(myBrowser.scrollView.contentOffset), forKey: "scroll_offset")
userDefaults.synchronize()
viewLaidoutSubviews = false
}
// Retrieve and set your content offset when the view re-appears
// and its subviews are first laid out
override func viewDidLayoutSubviews() {
if (!viewLaidoutSubviews) {
// If a scroll_offset is store in NSUserDefaults, use it
var userDefaults = NSUserDefaults.standardUserDefaults()
var scrollOffset:CGPoint? = CGPointFromString(userDefaults.valueForKey("scroll_offset") as? NSString)
if let position:CGPoint = scrollOffset {
myBrowser.scrollView.delegate = self
myBrowser.scrollView.setContentOffset(position, animated: false)
}
viewLaidoutSubviews = true
}
}
And utilize you UIWebView's webViewDidFinishLoad delegate method to update the scroll offset in the case that the web view didn't finish rendering before the view laid out its subviews:
// Retrieve and set your content offset once the web view has
// finished rendering (in case it hasn't finished rendering
// by the time the view's subviews were laid out)
func webViewDidFinishLoad(webView: UIWebView) {
// If a scroll_offset is store in NSUserDefaults, use it
var userDefaults = NSUserDefaults.standardUserDefaults()
var scrollOffset:CGPoint? = CGPointFromString(userDefaults.valueForKey("scroll_offset") as? NSString)
if let position:CGPoint = scrollOffset {
myBrowser.scrollView.delegate = self
myBrowser.scrollView.setContentOffset(position, animated: true)
}
}
But note, your NSUserDefaults value will also persist between app launches unless you delete it.