我需要执行一个动作(清空一个数组),当UINavigationController的后退按钮被按下,而按钮仍然导致堆栈上的前一个ViewController出现。我如何使用swift来实现这一点?


当前回答

这并不像我们想象的那么难。只需要为UIButton创建一个背景颜色清晰的框架,为按钮分配动作,并放置在导航栏后退按钮上。最后在使用后取下按钮。

这是Swift 3 用UIImage代替UIButton的示例代码

override func viewDidLoad() {
    super.viewDidLoad()
    let imageView = UIImageView()
    imageView.backgroundColor = UIColor.clear
    imageView.frame = CGRect(x:0,y:0,width:2*(self.navigationController?.navigationBar.bounds.height)!,height:(self.navigationController?.navigationBar.bounds.height)!)
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(back(sender:)))
    imageView.isUserInteractionEnabled = true
    imageView.addGestureRecognizer(tapGestureRecognizer)
    imageView.tag = 1
    self.navigationController?.navigationBar.addSubview(imageView)
    }

编写需要执行的代码

func back(sender: UIBarButtonItem) {

    // Perform your custom actions}
    _ = self.navigationController?.popViewController(animated: true)

    }

执行操作后删除子视图

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    for view in (self.navigationController?.navigationBar.subviews)!{
        if view.tag == 1 {
            view.removeFromSuperview()
        }
    }

其他回答

如果你正在使用navigationController,那么将UINavigationControllerDelegate协议添加到类中,并添加delegate方法,如下所示:

class ViewController:UINavigationControllerDelegate {

    func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController,
animated: Bool) {
        if viewController === self {
            // do here what you want
        }
    }
}

每当导航控制器滑到新屏幕时,就调用此方法。如果返回按钮被按下,新的视图控制器就是ViewController本身。

我通过调用/重写viewWillDisappear来实现这一点,然后像这样访问navigationController的堆栈:

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)

    let stack = self.navigationController?.viewControllers.count

    if stack >= 2 {
        // for whatever reason, the last item on the stack is the TaskBuilderViewController (not self), so we only use -1 to access it
        if let lastitem = self.navigationController?.viewControllers[stack! - 1] as? theViewControllerYoureTryingToAccess {
            // hand over the data via public property or call a public method of theViewControllerYoureTryingToAccess, like
            lastitem.emptyArray()
            lastitem.value = 5
        }
    }
}

斯威夫特4.2:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    if self.isMovingFromParent {
        // Your code...

    }
}

这里有一个最简单的Swift 5解决方案,它不需要你创建一个自定义的后退按钮,也不需要你放弃所有免费获得的UINavigationController左键功能。

正如Brandon A上面建议的那样,你需要在你想要与之交互的视图控制器中实现UINavigationControllerDelegate。一个好方法是创建一个unwind segue,你可以手动或自动地执行,并从自定义完成按钮或后退按钮重用相同的代码。

首先,让你感兴趣的视图控制器(你想检测返回的那个)在它的viewDidLoad中成为导航控制器的委托:

override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.delegate = self
}

其次,在文件底部添加一个扩展,覆盖navigationController(willShow:animated:)

extension PickerTableViewController: UINavigationControllerDelegate {

    func navigationController(_ navigationController: UINavigationController,
                              willShow viewController: UIViewController,
                              animated: Bool) {

        if let _ = viewController as? EditComicBookViewController {

            let selectedItemRow = itemList.firstIndex(of: selectedItemName)
            selectedItemIndex = IndexPath(row: selectedItemRow!, section: 0)

            if let selectedCell = tableView.cellForRow(at: selectedItemIndex) {
                performSegue(withIdentifier: "PickedItem", sender: selectedCell)
            }
        }
    }
}

因为你的问题包含了一个UITableViewController,所以我包含了一种获取用户点击行的索引路径的方法。

对于Swift 5,我们可以检查它在视图中是否会消失

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    if self.isMovingFromParent {
        delegate?.passValue(clickedImage: selectedImage)
    }
}