Exécuter une action lorsque le button de barre arrière de UINavigationController est pressé

J'ai besoin d'exécuter une action (vider un tableau), quand le button arrière d'un UINavigationController est pressé, alors que le button provoque toujours l'apparition du précédent ViewController sur la stack. Comment pourrais-je accomplir cela en utilisant swift? entrez la description de l'image ici

Une option serait la mise en œuvre de votre propre button de return personnalisé. Vous devrez append le code suivant à votre méthode 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]; } 

METTRE À JOUR:

Voici la version pour 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) } 

MISE À JOUR 2:

Voici la version de 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) } 

Remplacer le button par un button personnalisé comme suggéré sur une autre réponse n'est peut-être pas une bonne idée car vous perdrez le comportement et le style par défaut.

Une autre option que vous avez est d'implémenter la méthode viewWillDisappear sur View Controller et vérifier une propriété nommée isMovingFromParentViewController . Si cette propriété est vraie, cela signifie que le controller de vue est en train de disparaître, car il est supprimé (sauté).

Devrait ressembler à quelque chose comme:

 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.") } } 

J'ai créé cette class (swift) pour créer un button de return exactement comme le précédent, y compris la flèche de return. Il peut créer un button avec du text régulier ou avec une image.

Usage

 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

(code pour dessiner la flèche de return créée avec le plugin Sketch & Paintcode)

 class CustomBackButton: NSObject { class func createWithText(text: Ssortingng, 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), forBarMesortingcs: UIBarMesortingcs.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: Ssortingng, 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: UIBarMesortingcs.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 } } } 

Si vous utilisez navigationController ajoutez le protocole UINavigationControllerDelegate à la class et ajoutez la méthode déléguée comme suit:

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

Cette méthode est appelée à chaque fois que le controller de navigation glisse vers un nouvel écran. Si le button Précédent a été enfoncé, le nouveau controller de vue est ViewController lui-même.

J'ai été capable de réaliser ceci avec:

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

Pas besoin de button de return personnalisé.

J'ai accompli cela en appelant / viewWillDisappear puis en accédant à la stack de navigationController comme ceci:

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

Comme je comprends, vous voulez vider votre array que vous appuyez sur votre button de return et pop à votre précédent ViewController let votre Array que vous avez chargé sur cet écran est

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

NON

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

Cela sera appelé même si vous passez au controller de vue dans lequel vous utilisez cette méthode. Dans quelle vérification si le " parent " est nil de n'est pas une manière précise d'être sûr de revenir au UIViewController correct. Pour déterminer exactement si UINavigationController navigue correctement vers le UIViewController qui a présenté celui-ci, vous devrez vous conformer au protocole UINavigationControllerDelegate .

OUI

note: MyViewController est juste le nom de tout UIViewController vous voulez détecter le return.

1) En haut de votre file, ajoutez UINavigationControllerDelegate .

 class MyViewController: UIViewController, UINavigationControllerDelegate { 

2) Ajoutez une propriété à votre class qui gardera trace du UIViewController que vous êtes en train de UIViewController .

 class MyViewController: UIViewController, UINavigationControllerDelegate { var previousViewController:UIViewController 

3) dans la méthode viewDidLoad , assignez-vous en tant que délégué pour votre UINavigationController .

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

3) Avant de commencer , assignez le précédent UIViewController tant que cette propriété.

 // 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) Et se conformer à une méthode dans MyViewController de UINavigationControllerDelegate

 func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { if viewController == self.previousViewController { // You are going back } } 

Ce n'est pas difficile comme nous le pensons. Créez simplement un cadre pour UIButton avec une couleur d'arrière-plan claire, atsortingbuez une action au button et placez-le sur le button de return de la barre de navigation. Et enfin, retirez le button après utilisation.

Voici l'exemple de code Swift 3 fait avec UIImage au lieu de 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) } 

écrire le code doit être exécuté

 func back(sender: UIBarButtonItem) { // Perform your custom actions} _ = self.navigationController?.popViewController(animated: true) } 

Supprimer la sous-vue après l'exécution de l'action

 override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) for view in (self.navigationController?.navigationBar.subviews)!{ if view.tag == 1 { view.removeFromSuperview() } } 

Essaye ça .

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

Essayez ceci aussi.

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

Dans mon cas, viewWillDisappear fonctionnait mieux. Mais dans certains cas, il faut modifier le controller de vue précédent. Donc, voici ma solution avec l'access au controller de vue précédente et cela fonctionne dans 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") } }