按下UINavigationController的后退button时执行动作

当按下UINavigationController的后退button时,我需要执行一个操作(清空数组),同时button仍然会导致堆栈中的前一个ViewController出现。 我怎么能用swift来完成这个? 在这里输入图像说明

一个选项是实现您自己的自定义后退button。 您需要将以下代码添加到您的viewDidLoad方法中:

 - (void) viewDidLoad { [super viewDidLoad]; self.navigationItem.hidesBackButton = YES; UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStyleBordered target:self action:@selector(back:)]; self.navigationItem.leftBarButtonItem = newBackButton; } - (void) back:(UIBarButtonItem *)sender { // Perform your custom actions // ... // Go back to the previous ViewController [self.navigationController popViewControllerAnimated:YES]; } 

更新:

这里是Swift的版本:

  override func viewDidLoad { super.viewDidLoad() self.navigationItem.hidesBackButton = true let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Bordered, target: self, action: "back:") self.navigationItem.leftBarButtonItem = newBackButton } func back(sender: UIBarButtonItem) { // Perform your custom actions // ... // Go back to the previous ViewController self.navigationController?.popViewControllerAnimated(true) } 

更新2:

这里是Swift 3的版本:

  override func viewDidLoad { super.viewDidLoad() self.navigationItem.hidesBackButton = true let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(YourViewController.back(sender:))) self.navigationItem.leftBarButtonItem = newBackButton } func back(sender: UIBarButtonItem) { // Perform your custom actions // ... // Go back to the previous ViewController _ = navigationController?.popViewController(animated: true) } 

将buttonreplace为另一个答案中build议的自定义button可能不是一个好主意,因为您将失去默认行为和样式。

另一个选项是在View Controller上实现viewWillDisappear方法,并检查名为isMovingFromParentViewController的属性。 如果该属性为真,则意味着视图控制器正在消失,因为它被删除(popup)。

应该看起来像这样:

 override func viewWillDisappear(animated : Bool) { super.viewWillDisappear(animated) if self.isMovingFromParentViewController { // Your code... } } 
 override func willMove(toParentViewController parent: UIViewController?) { super.willMove(toParentViewController: parent) if parent == nil { print("This VC is 'will' be popped. ie the back button was pressed.") } } 

我创build了这个(swift)类来创build一个和常规类似的后退button,包括后退箭头。 它可以创build一个常规的文字或图像的button。

用法

 weak var weakSelf = self // Assign back button with back arrow and text (exactly like default back button) navigationItem.leftBarButtonItems = CustomBackButton.createWithText("YourBackButtonTitle", color: UIColor.yourColor(), target: weakSelf, action: #selector(YourViewController.tappedBackButton)) // Assign back button with back arrow and image navigationItem.leftBarButtonItems = CustomBackButton.createWithImage(UIImage(named: "yourImageName")!, color: UIColor.yourColor(), target: weakSelf, action: #selector(YourViewController.tappedBackButton)) func tappedBackButton() { // Do your thing self.navigationController!.popViewControllerAnimated(true) } 

CustomBackButtonClass

(用于绘制使用Sketch&Paintcode插件创build的后退箭头的代码)

 class CustomBackButton: NSObject { class func createWithText(text: String, color: UIColor, target: AnyObject?, action: Selector) -> [UIBarButtonItem] { let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil) negativeSpacer.width = -8 let backArrowImage = imageOfBackArrow(color: color) let backArrowButton = UIBarButtonItem(image: backArrowImage, style: UIBarButtonItemStyle.Plain, target: target, action: action) let backTextButton = UIBarButtonItem(title: text, style: UIBarButtonItemStyle.Plain , target: target, action: action) backTextButton.setTitlePositionAdjustment(UIOffset(horizontal: -12.0, vertical: 0.0), forBarMetrics: UIBarMetrics.Default) return [negativeSpacer, backArrowButton, backTextButton] } class func createWithImage(image: UIImage, color: UIColor, target: AnyObject?, action: Selector) -> [UIBarButtonItem] { // recommended maximum image height 22 points (ie 22 @1x, 44 @2x, 66 @3x) let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil) negativeSpacer.width = -8 let backArrowImageView = UIImageView(image: imageOfBackArrow(color: color)) let backImageView = UIImageView(image: image) let customBarButton = UIButton(frame: CGRectMake(0,0,22 + backImageView.frame.width,22)) backImageView.frame = CGRectMake(22, 0, backImageView.frame.width, backImageView.frame.height) customBarButton.addSubview(backArrowImageView) customBarButton.addSubview(backImageView) customBarButton.addTarget(target, action: action, forControlEvents: .TouchUpInside) return [negativeSpacer, UIBarButtonItem(customView: customBarButton)] } private class func drawBackArrow(frame frame: CGRect = CGRect(x: 0, y: 0, width: 14, height: 22), color: UIColor = UIColor(hue: 0.59, saturation: 0.674, brightness: 0.886, alpha: 1), resizing: ResizingBehavior = .AspectFit) { /// General Declarations let context = UIGraphicsGetCurrentContext()! /// Resize To Frame CGContextSaveGState(context) let resizedFrame = resizing.apply(rect: CGRect(x: 0, y: 0, width: 14, height: 22), target: frame) CGContextTranslateCTM(context, resizedFrame.minX, resizedFrame.minY) let resizedScale = CGSize(width: resizedFrame.width / 14, height: resizedFrame.height / 22) CGContextScaleCTM(context, resizedScale.width, resizedScale.height) /// Line let line = UIBezierPath() line.moveToPoint(CGPoint(x: 9, y: 9)) line.addLineToPoint(CGPoint.zero) CGContextSaveGState(context) CGContextTranslateCTM(context, 3, 11) line.lineCapStyle = .Square line.lineWidth = 3 color.setStroke() line.stroke() CGContextRestoreGState(context) /// Line Copy let lineCopy = UIBezierPath() lineCopy.moveToPoint(CGPoint(x: 9, y: 0)) lineCopy.addLineToPoint(CGPoint(x: 0, y: 9)) CGContextSaveGState(context) CGContextTranslateCTM(context, 3, 2) lineCopy.lineCapStyle = .Square lineCopy.lineWidth = 3 color.setStroke() lineCopy.stroke() CGContextRestoreGState(context) CGContextRestoreGState(context) } private class func imageOfBackArrow(size size: CGSize = CGSize(width: 14, height: 22), color: UIColor = UIColor(hue: 0.59, saturation: 0.674, brightness: 0.886, alpha: 1), resizing: ResizingBehavior = .AspectFit) -> UIImage { var image: UIImage UIGraphicsBeginImageContextWithOptions(size, false, 0) drawBackArrow(frame: CGRect(origin: CGPoint.zero, size: size), color: color, resizing: resizing) image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } private enum ResizingBehavior { case AspectFit /// The content is proportionally resized to fit into the target rectangle. case AspectFill /// The content is proportionally resized to completely fill the target rectangle. case Stretch /// The content is stretched to match the entire target rectangle. case Center /// The content is centered in the target rectangle, but it is NOT resized. func apply(rect rect: CGRect, target: CGRect) -> CGRect { if rect == target || target == CGRect.zero { return rect } var scales = CGSize.zero scales.width = abs(target.width / rect.width) scales.height = abs(target.height / rect.height) switch self { case .AspectFit: scales.width = min(scales.width, scales.height) scales.height = scales.width case .AspectFill: scales.width = max(scales.width, scales.height) scales.height = scales.width case .Stretch: break case .Center: scales.width = 1 scales.height = 1 } var result = rect.standardized result.size.width *= scales.width result.size.height *= scales.height result.origin.x = target.minX + (target.width - result.width) / 2 result.origin.y = target.minY + (target.height - result.height) / 2 return result } } } 

SWIFT 3.0

 class CustomBackButton: NSObject { class func createWithText(text: String, color: UIColor, target: AnyObject?, action: Selector) -> [UIBarButtonItem] { let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil) negativeSpacer.width = -8 let backArrowImage = imageOfBackArrow(color: color) let backArrowButton = UIBarButtonItem(image: backArrowImage, style: UIBarButtonItemStyle.plain, target: target, action: action) let backTextButton = UIBarButtonItem(title: text, style: UIBarButtonItemStyle.plain , target: target, action: action) backTextButton.setTitlePositionAdjustment(UIOffset(horizontal: -12.0, vertical: 0.0), for: UIBarMetrics.default) return [negativeSpacer, backArrowButton, backTextButton] } class func createWithImage(image: UIImage, color: UIColor, target: AnyObject?, action: Selector) -> [UIBarButtonItem] { // recommended maximum image height 22 points (ie 22 @1x, 44 @2x, 66 @3x) let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil) negativeSpacer.width = -8 let backArrowImageView = UIImageView(image: imageOfBackArrow(color: color)) let backImageView = UIImageView(image: image) let customBarButton = UIButton(frame: CGRect(x: 0, y: 0, width: 22 + backImageView.frame.width, height: 22)) backImageView.frame = CGRect(x: 22, y: 0, width: backImageView.frame.width, height: backImageView.frame.height) customBarButton.addSubview(backArrowImageView) customBarButton.addSubview(backImageView) customBarButton.addTarget(target, action: action, for: .touchUpInside) return [negativeSpacer, UIBarButtonItem(customView: customBarButton)] } private class func drawBackArrow(_ frame: CGRect = CGRect(x: 0, y: 0, width: 14, height: 22), color: UIColor = UIColor(hue: 0.59, saturation: 0.674, brightness: 0.886, alpha: 1), resizing: ResizingBehavior = .AspectFit) { /// General Declarations let context = UIGraphicsGetCurrentContext()! /// Resize To Frame context.saveGState() let resizedFrame = resizing.apply(CGRect(x: 0, y: 0, width: 14, height: 22), target: frame) context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) let resizedScale = CGSize(width: resizedFrame.width / 14, height: resizedFrame.height / 22) context.scaleBy(x: resizedScale.width, y: resizedScale.height) /// Line let line = UIBezierPath() line.move(to: CGPoint(x: 9, y: 9)) line.addLine(to: CGPoint.zero) context.saveGState() context.translateBy(x: 3, y: 11) line.lineCapStyle = .square line.lineWidth = 3 color.setStroke() line.stroke() context.restoreGState() /// Line Copy let lineCopy = UIBezierPath() lineCopy.move(to: CGPoint(x: 9, y: 0)) lineCopy.addLine(to: CGPoint(x: 0, y: 9)) context.saveGState() context.translateBy(x: 3, y: 2) lineCopy.lineCapStyle = .square lineCopy.lineWidth = 3 color.setStroke() lineCopy.stroke() context.restoreGState() context.restoreGState() } private class func imageOfBackArrow(_ size: CGSize = CGSize(width: 14, height: 22), color: UIColor = UIColor(hue: 0.59, saturation: 0.674, brightness: 0.886, alpha: 1), resizing: ResizingBehavior = .AspectFit) -> UIImage { var image: UIImage UIGraphicsBeginImageContextWithOptions(size, false, 0) drawBackArrow(CGRect(origin: CGPoint.zero, size: size), color: color, resizing: resizing) image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return image } private enum ResizingBehavior { case AspectFit /// The content is proportionally resized to fit into the target rectangle. case AspectFill /// The content is proportionally resized to completely fill the target rectangle. case Stretch /// The content is stretched to match the entire target rectangle. case Center /// The content is centered in the target rectangle, but it is NOT resized. func apply(_ rect: CGRect, target: CGRect) -> CGRect { if rect == target || target == CGRect.zero { return rect } var scales = CGSize.zero scales.width = abs(target.width / rect.width) scales.height = abs(target.height / rect.height) switch self { case .AspectFit: scales.width = min(scales.width, scales.height) scales.height = scales.width case .AspectFill: scales.width = max(scales.width, scales.height) scales.height = scales.width case .Stretch: break case .Center: scales.width = 1 scales.height = 1 } var result = rect.standardized result.size.width *= scales.width result.size.height *= scales.height result.origin.x = target.minX + (target.width - result.width) / 2 result.origin.y = target.minY + (target.height - result.height) / 2 return result } } } 

如果您使用的是navigationController那么将UINavigationControllerDelegate协议添加到类中并添加委托方法,如下所示:

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

只要导航控制器将滑动到新的屏幕,就会调用此方法。 如果后退button被按下,新的视图控制器是ViewController本身。

我能够通过以下方式实现这一点:

 override func didMoveToParentViewController(parent: UIViewController?) { super.didMoveToParentViewController(parent) if parent == nil{ println("Back Button pressed.") delegate?.goingBack() } } 

无需自定义后退button。

我通过调用/覆盖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 } } } 

据我所知,你想要清空你的array当你按下你的后退button,并popup到您以前的ViewController let你在这个屏幕上加载的Array

 let settingArray = NSMutableArray() @IBAction func Back(sender: AnyObject) { self. settingArray.removeAllObjects() self.dismissViewControllerAnimated(true, completion: nil) } 
  override public func viewDidLoad() { super.viewDidLoad() self.navigationController?.navigationBar.topItem?.title = GlobalVariables.selectedMainIconName let image = UIImage(named: "back-btn") image = image?.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal) self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: image, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(Current[enter image description here][1]ViewController.back) ) } func back() { self.navigationController?.popToViewController( self.navigationController!.viewControllers[ self.navigationController!.viewControllers.count - 2 ], animated: true) } 

没有

override func willMove(toParentViewController parent: UIViewController?) { }

即使你正在重写这个方法的视图控制器,它也会被调用。 其中检查“ parent ”是不是不是一个确切的方式来确定回到正确的UIViewController 。 要确定UINavigationController是否正确导航回到提供当前UIViewController ,您将需要符合UINavigationControllerDelegate协议。

注意: MyViewController只是您想要检测的任何UIViewController的名称。

1)在文件顶部添加UINavigationControllerDelegate

 class MyViewController: UIViewController, UINavigationControllerDelegate { 

2)添加一个属性到你的类将跟踪你inheritance的UIViewController

 class MyViewController: UIViewController, UINavigationControllerDelegate { var previousViewController:UIViewController 

3)在MyViewControllerviewDidLoad方法中指定self作为你的UINavigationController的委托。

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

3) 在你继续之前 ,把前一个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 } } 

这不是因为我们的事情。 只需为背景颜色清晰的UIButton创build一个框架,为该button分配操作并放置在导航栏的后退button上。 最后使用后取下button。

这里是用UIImage而不是UIButton完成的Swift 3示例代码

 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() } } 

尝试这个 。

 self.navigationItem.leftBarButtonItem?.target = "methodname" func methodname ( ) { // enter code here } 

试试这个。

 override func viewWillAppear(animated: Bool) { //empty your array } 

在我看来, viewWillDisappear效果最好。 但在某些情况下,必须修改以前的视图控制器。 所以这里是我的解决scheme,访问以前的视图控制器 ,它在Swift 4中工作

 override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if isMovingFromParentViewController { if let viewControllers = self.navigationController?.viewControllers { if (viewControllers.count >= 1) { let previousViewController = viewControllers[viewControllers.count-1] as! NameOfDestinationViewController // whatever you want to do previousViewController.callOrModifySomething() } } } } 

Swift 3:

 override func didMove(toParentViewController parent: UIViewController?) { super.didMove(toParentViewController: parent) if parent == nil{ print("Back button was clicked") } }