我需要执行一个动作(清空一个数组),当UINavigationController的后退按钮被按下,而按钮仍然导致堆栈上的前一个ViewController出现。我如何使用swift来实现这一点?
当前回答
你可以子类化UINavigationController并重写popViewController(animated: Bool)。除了能够在那里执行一些代码,你还可以防止用户完全返回,例如提示保存或丢弃他当前的工作。
示例实现,其中您可以设置popHandler,由推送的控制器设置/清除。
class NavigationController: UINavigationController
{
var popHandler: (() -> Bool)?
override func popViewController(animated: Bool) -> UIViewController?
{
guard self.popHandler?() != false else
{
return nil
}
self.popHandler = nil
return super.popViewController(animated: animated)
}
}
以及来自跟踪未保存工作的推送控制器的示例使用情况。
let hasUnsavedWork: Bool = // ...
(self.navigationController as! NavigationController).popHandler = hasUnsavedWork ?
{
// Prompt saving work here with an alert
return false // Prevent pop until as user choses to save or discard
} : nil // No unsaved work, we clear popHandler to let it pop normally
作为一个很好的触摸,这也将被interactivePopGestureRecognizer调用,当用户试图返回使用滑动手势。
其他回答
如果你想有后退按钮和后退箭头,你可以使用下面的图片和代码
backArrow.png backArrow@2x.png backArrow@3x.png
override func viewDidLoad() {
super.viewDidLoad()
let customBackButton = UIBarButtonItem(image: UIImage(named: "backArrow") , style: .plain, target: self, action: #selector(backAction(sender:)))
customBackButton.imageInsets = UIEdgeInsets(top: 2, left: -8, bottom: 0, right: 0)
navigationItem.leftBarButtonItem = customBackButton
}
func backAction(sender: UIBarButtonItem) {
// custom actions here
navigationController?.popViewController(animated: true)
}
NO
override func willMove(父控件:UIViewController?) {}
即使你在segue到覆盖这个方法的视图控制器,这个也会被调用。其中,检查parent是否为nil或not不是确保移动回正确的UIViewController的精确方法。为了准确地确定UINavigationController是否正确地导航回呈现当前的UIViewController,你将需要遵守UINavigationControllerDelegate协议。
YES
注意:MyViewController只是你想要检测返回的UIViewController的名称。
1)在你的文件顶部添加UINavigationControllerDelegate。
class MyViewController: UIViewController, UINavigationControllerDelegate {
2)添加一个属性到你的类,它将跟踪你正在segue的UIViewController。
class MyViewController: UIViewController, UINavigationControllerDelegate {
var previousViewController:UIViewController
3)在MyViewController的viewDidLoad方法中为你的UINavigationController分配self作为委托。
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.delegate = self
}
3)在你segue之前,将之前的UIViewController分配为这个属性。
// In previous UIViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "YourSegueID" {
if let nextViewController = segue.destination as? MyViewController {
nextViewController.previousViewController = self
}
}
}
4)并遵循UINavigationControllerDelegate的MyViewController中的一个方法
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if viewController == self.previousViewController {
// You are going back
}
}
Swift 5 __ Xcode 11.5
在我的情况下,我想做一个动画,当它完成后,返回。 一种覆盖后退按钮默认动作的方法 调用你的自定义动作是这样的:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setBtnBack()
}
private func setBtnBack() {
for vw in navigationController?.navigationBar.subviews ?? [] where "\(vw.classForCoder)" == "_UINavigationBarContentView" {
print("\(vw.classForCoder)")
for subVw in vw.subviews where "\(subVw.classForCoder)" == "_UIButtonBarButton" {
let ctrl = subVw as! UIControl
ctrl.removeTarget(ctrl.allTargets.first, action: nil, for: .allEvents)
ctrl.addTarget(self, action: #selector(backBarBtnAction), for: .touchUpInside)
}
}
}
@objc func backBarBtnAction() {
doSomethingBeforeBack { [weak self](isEndedOk) in
if isEndedOk {
self?.navigationController?.popViewController(animated: true)
}
}
}
private func doSomethingBeforeBack(completion: @escaping (_ isEndedOk:Bool)->Void ) {
UIView.animate(withDuration: 0.25, animations: { [weak self] in
self?.vwTxt.alpha = 0
}) { (isEnded) in
completion(isEnded)
}
}
或者你可以使用这个方法一次来探索NavigationBar视图层次结构,并获得访问_UIButtonBarButton视图的索引,转换为UIControl,删除目标-动作,并添加你的自定义目标-动作:
private func debug_printSubviews(arrSubviews:[UIView]?, level:Int) {
for (i,subVw) in (arrSubviews ?? []).enumerated() {
var str = ""
for _ in 0...level {
str += "\t"
}
str += String(format: "%2d %@",i, "\(subVw.classForCoder)")
print(str)
debug_printSubviews(arrSubviews: subVw.subviews, level: level + 1)
}
}
// Set directly the indexs
private func setBtnBack_method2() {
// Remove or comment the print lines
debug_printSubviews(arrSubviews: navigationController?.navigationBar.subviews, level: 0)
let ctrl = navigationController?.navigationBar.subviews[1].subviews[0] as! UIControl
print("ctrl.allTargets: \(ctrl.allTargets)")
ctrl.removeTarget(ctrl.allTargets.first, action: nil, for: .allEvents)
print("ctrl.allTargets: \(ctrl.allTargets)")
ctrl.addTarget(self, action: #selector(backBarBtnAction), for: .touchUpInside)
print("ctrl.allTargets: \(ctrl.allTargets)")
}
试试这个。
self.navigationItem.leftBarButtonItem?.target = "methodname"
func methodname ( ) {
// enter code here
}
这个也试试。
override func viewWillAppear(animated: Bool) {
//empty your array
}
当返回按钮按下,忽略交互式弹出与屏幕边缘手势。
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isMovingFromParent, transitionCoordinator?.isInteractive == false {
// code here
}
}