按下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)在MyViewController
的viewDidLoad
方法中指定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") } }