habed
habed

Reputation: 201

Tab Navigation Bar Consistency

I have a navigation tab bar with different few tabs. I would want to have a functionality that when I press on a tab it would always bring me to the view regardless of where I am.

For example:

"Manuals" a tab bar "Open Documents" another tab bar

When navigating to the manuals view by hitting "Manuals" and then hitting open document; I would want to expected to see the list of open data modules instead I jump to the "last open data module".

How can I achieve this?

The code for "Open Documents" is below:

class DocumentListViewController: BaseViewController {

// MARK: - IB Outlets
@IBOutlet weak var tableView: UITableView!

// MARK: - Properties
var webview:WKWebView!
var documentsToDelete:[Node]?

// MARK: - VC Life Cycle
override func viewDidLoad() {

    super.viewDidLoad()

    title = NSLocalizedString("Open Documents", comment: "")

    tableView.delegate = self
    tableView.dataSource = self
    tableView.register(UINib(nibName: "TablistHeader", bundle: Bundle.main), forHeaderFooterViewReuseIdentifier: "Header")

    webview = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
    webview.navigationDelegate = self

}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    tableView.reloadData()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

//MARK: - Business Logic
func remove(documents nodes:[Node]) {

    documentsToDelete = nodes

    if let section = nodes.first?.sections.first, let urlString = section["url"], let nodePath = nodes.first?.path {

        var readAccessFolder:URL?
        let pathComponents = URL(fileURLWithPath: nodePath).pathComponents

        if pathComponents.count >= 2 {

            let rootFolder = "\(pathComponents[1])"
            readAccessFolder = URL(fileURLWithPath: "\(PackageManager.shared.packageFolder)\(rootFolder)")
        }

        let url = URL(fileURLWithPath: urlString)
        _ = webview.loadFileURL(url, allowingReadAccessTo: readAccessFolder!)

    }
    else {
        deleteDocumentsFromList()
    }

}

fileprivate func deleteDocumentsFromList() {

    if let indexes = self.documentsToDelete?.flatMap({ (node) -> Int? in
        return PackageManager.shared.openNodes.index(of: node)
    })
    {

        for i in indexes.reversed() {
            PackageManager.shared.openNodes.remove(at: i)
        }

        self.tableView.reloadData()
        webview.load(URLRequest(url: URL(string:"about:blank")!))
    }

}

func resetProcedureStepCheckboxes() {

    if let dmcs = documentsToDelete?.flatMap({ (node) -> String? in
        return node.moduleCode
    })
    {
        webview.evaluateJavaScript("resetProcedureStepCheckboxes(\(dmcs))") { (result, error) in
            print(error as Any)
            self.deleteDocumentsFromList()
        }

    }

}

override func showDocumentViewController(for node:Node?, openSegment segment:Int = 0) {

    let contentView = self.storyboard?.instantiateViewController(withIdentifier: "DocumentViewController") as! DocumentViewController
    contentView.currentNode = node
    contentView.initalSegment = segment
    contentView.navigationItem.titleView = UILabel.forTitleView(withText: node?.title)

    navigationController?.pushViewController(contentView, animated: true)

}

}

// MARK: - UITableViewDataSource
extension DocumentListViewController : UITableViewDataSource {

func numberOfSections(in tableView: UITableView) -> Int {

    if PackageManager.shared.openNodes.count > 0 {
        tableView.removeEmptyMessage()
        return 1
    } else {
        tableView.showEmptyMessage(message: NSLocalizedString("No open documents", comment: ""), viewController: self)
        return 0
    }

}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return PackageManager.shared.openNodes.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let node = PackageManager.shared.openNodes[indexPath.row]
    var dText = ""

    if let man = node.manual {
        dText = "\(man)\n"
    }

    if let mc = node.moduleCode {
        dText = "\(dText)" + "\(mc)"
    }

    let cell = tableView.dequeueReusableCell(withIdentifier: "OpenDocumentCell", for: indexPath)
    cell.imageView?.image = node.image()
    cell.imageView?.contentMode = .scaleAspectFill
    cell.editingAccessoryType = .none
    cell.accessoryType = .disclosureIndicator
    cell.textLabel?.text = node.title

    cell.detailTextLabel?.numberOfLines = 0
    cell.detailTextLabel?.text = dText

    return cell

}

}

// MARK: - UITableViewDelegate
extension DocumentListViewController : UITableViewDelegate {

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 60
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    tableView.deselectRow(at: indexPath, animated: true)

    let node = PackageManager.shared.openNodes[indexPath.row]
    showDocumentViewController(for: node)

}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

    if PackageManager.shared.openNodes.count == 0 {
        return 0
    }

    return 50
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    if PackageManager.shared.openNodes.count == 0 {
        return nil
    }

    let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "Header") as! TablistHeader
    header.titleLabel.text = String.localizedStringWithFormat(NSLocalizedString("%i open documents", comment: ""), PackageManager.shared.openNodes.count)
    header.onDelete = { [weak self] in

        guard let strongSelf = self else { return }

        // show action sheet
        let title =  NSLocalizedString("Clear list", comment: "")
        let msg =  NSLocalizedString("Do you really want to clear the list of open documents?", comment: "")
        let options = UIAlertController(title:title, message: msg, preferredStyle: .alert)

        let deleteAll = UIAlertAction(title: NSLocalizedString("Clear list", comment: ""),
                                      style:.destructive,
                                      handler: { (action) -> Void in

                                        strongSelf.remove(documents: PackageManager.shared.openNodes)

        })
        options.addAction(deleteAll)

        let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""),
                                   style:.cancel,
                                   handler: nil)
        options.addAction(cancel)

        strongSelf.present(options, animated: true, completion: nil)

    }
    return header

}

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

    let del = UITableViewRowAction(style: .destructive, title: NSLocalizedString("Delete", comment: ""), handler: { [weak self] (action, indexPath) -> Void in

        guard let strongSelf = self else { return }

        let node = PackageManager.shared.openNodes[indexPath.row]
        strongSelf.remove(documents: [node])

    })

    return [del]

}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
}

}

// MARK: - WKNavigationDelegate
extension DocumentListViewController : WKNavigationDelegate {

func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
}

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    resetProcedureStepCheckboxes()
}

func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
    print(error)
}

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

    if let abs = navigationAction.request.url?.absoluteString, abs == "about:blank" {
        decisionHandler(.cancel)
    }

    decisionHandler(.allow)
}

}

Upvotes: 0

Views: 85

Answers (2)

habed
habed

Reputation: 201

Fixed. All I had to do was to set UITabBarController in my RootTabBarViewController and set "delegate = self" in viewDidLoad() and implement the below function:

func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if tabBarController.selectedIndex == 1 {

   if let vc = viewController as? UINavigationController {          
   vc.popViewController(animated: false)
   }
}

Upvotes: 1

toddg
toddg

Reputation: 2906

You could set your UITabBarControllerDelegate and then implement shouldSelectViewController:

func tabBarController(_ tabBarController: UITabBarController, 
              shouldSelect viewController: UIViewController) -> Bool {

    // check if tabBarController.selectedViewController is navController
    // containing your detailViewController. If so:

    navController.popViewController(animated: false)
    return true
}

This may be poor UX if it pops back to your tableview while it's still in view. Another option would be to wait until the transition is complete and then pop the viewController after it's out of view.

Upvotes: 1

Related Questions