按下UINavigationController的后退按钮时执行操作

Ste*_*enR 183 xcode uinavigationcontroller ios swift

UINavigationController按下a的后退按钮时,我需要执行一个动作(清空一个数组),而按钮仍然会使ViewController堆栈中的前一个按钮出现.我怎么能用swift完成这个? 在此输入图像描述

man*_*sta 441

根据另一个答案的建议将按钮替换为自定义按钮可能不是一个好主意,因为您将失去默认行为和样式.

另一个选项是在View Controller上实现viewWillDisappear方法,并检查名为isMovingFromParentViewController的属性.如果该属性为true,则表示视图控制器正在消失,因为它正被删除(弹出).

应该看起来像:

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

    if self.isMovingFromParentViewController {
        // Your code...
    }
}
Run Code Online (Sandbox Code Playgroud)

在快速4.2

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

    if self.isMovingFromParent {
        // Your code...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你打个电话,```viewWillDisappear(动画:)```会被触发.这可能不是你想要的.可能更好地使用```willMove(toParentViewController:)``` (17认同)
  • 对于**Swift 3.1**:`override func viewWillDisappear(_ animated:Bool){super.viewWillDisappear(animated)if isMovingFromParentViewController {// Your code ...}}` (13认同)
  • @gmogames是的,你做不到.但问题并没有要求.为了能够停止返回的动作,我猜你真的需要覆盖按钮. (5认同)
  • 不,这是完全错误的。当按下后退按钮并且我们弹出到 ViewController 时,会调用此方法,然后调用此方法。问题是如何在 NavigationItem BackButton Click 中执行操作。这就像完成一样,我们可以在 ViewWillDisappear 中完成这件事。我希望你明白我所说的。有什么办法可以点击按钮然后请给我解决方案。谢谢 (2认同)
  • 不幸的是,当移动到任何新的视图控制器时,这也会被调用......但我只需要捕获后退按钮而无需捕获其他任何东西 (2认同)
  • 这怎么能得到这么多人的点赞呢?问题是,而不是默认行为需要检测何时点击后退按钮并执行操作... self.isMovingFromParent 将始终返回 true 如果用户已在此页面中导航。 (2认同)

fr3*_*33g 144

一种选择是实现自己的自定义后退按钮.您需要将以下代码添加到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];
}
Run Code Online (Sandbox Code Playgroud)

更新:

这是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)
    }
Run Code Online (Sandbox Code Playgroud)

更新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)
    }
Run Code Online (Sandbox Code Playgroud)

  • 我怎么能像普通的后退按钮一样有箭头? (81认同)
  • 替换系统按钮来覆盖功能不是一个好方法.最好的方法是下面的答案!http://stackoverflow.com/a/27715660/2307276 (5认同)
  • 这不会弹出到上一个视图控制器; 它会弹出到根视图控制器. (2认同)
  • @TomSawyer 为此,请查看下面的答案 (2认同)

Iya*_*Iya 54

override func willMove(toParent parent: UIViewController?)
{
    super.willMove(toParent: parent)
    if parent == nil
    {
        print("This VC is 'will' be popped. i.e. the back button was pressed.")
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在进入新VC时也会调用它,而不仅仅是在返回时. (3认同)
  • 在Swift3/iOS10中不起作用,控制台打印'嵌套的弹出动画可能导致导航栏损坏'. (2认同)
  • 这应该是公认的答案。当 `parent == nil` 是我们将 *back* 移到 `parent` 场景时 (2认同)

小智 28

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

斯威夫特3

override func didMoveToParentViewController(parent: UIViewController?) {
   super.didMoveToParentViewController(parent)

   if parent == nil {
      println("Back Button pressed.")
      delegate?.goingBack()
   }           
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特4

override func didMove(toParent parent: UIViewController?) {
    super.didMove(toParent: parent)

    if parent == nil {
        debugPrint("Back Button pressed.")
    }
}
Run Code Online (Sandbox Code Playgroud)

无需自定义后退按钮.


gui*_*ido 28

我创建了这个(swift)类来创建一个与常规按钮完全相同的后退按钮,包括后箭头.它可以创建一个包含常规文本或图像的按钮.

用法

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)
}
Run Code Online (Sandbox Code Playgroud)

CustomBackButtonClass

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

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 (i.e. 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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 (i.e. 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 嗨@guido,你的解决方案是完美的,我尝试了你的代码并注意到后面按钮前面有空间,即使你添加了负宽度的条形按钮. (2认同)

Les*_*ary 20

如果您想要带后退箭头的后退按钮,可以使用下面的图像和代码

backArrow.png arrow1 backArrow@2x.png arrow2 backArrow@3x.png arrow3

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)
}
Run Code Online (Sandbox Code Playgroud)


Aji*_*til 11

如果您正在使用,navigationController则将UINavigationControllerDelegate协议添加到类并添加委托方法,如下所示:

class ViewController:UINavigationControllerDelegate {

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

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


Riv*_*era 9

您可以子类化UINavigationController并覆盖popViewController(animated: Bool). 除了能够在那里执行一些代码之外,您还可以阻止用户完全返回,例如提示保存或放弃当前的工作。

示例实现,您可以在popHandler其中设置由推送控制器设置/清除的 a 。

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

以及来自跟踪未保存工作的推送控制器的示例使用情况。

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
Run Code Online (Sandbox Code Playgroud)

interactivePopGestureRecognizer作为一个很好的触摸,当用户尝试使用滑动手势返回时,也会调用此方法。


Паш*_*хин 7

按下后退按钮时,忽略屏幕边缘手势的交互式弹出。

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    if isMovingFromParent, transitionCoordinator?.isInteractive == false {
      // code here
    }
  }
Run Code Online (Sandbox Code Playgroud)


Bra*_*n A 6

没有

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

这将被调用,即使你是segueing 视图控制器中你重写此方法.在哪个检查" parent"是否nil不是一个确切的方法,以确保回到正确的方向UIViewController.要确切地确定是否UINavigationController正确导航回到UIViewController当前显示的那个,您将需要符合UINavigationControllerDelegate协议.

注意:MyViewController只是UIViewController您要检测的任何内容的名称.

1)在文件的顶部添加UINavigationControllerDelegate.

class MyViewController: UIViewController, UINavigationControllerDelegate {
Run Code Online (Sandbox Code Playgroud)

2)向您的班级添加一个属性,该属性将跟踪UIViewController您正在进行的调整.

class MyViewController: UIViewController, UINavigationControllerDelegate {

var previousViewController:UIViewController
Run Code Online (Sandbox Code Playgroud)

3)MyViewControllerviewDidLoad方法,分配self与委托你UINavigationController.

override func viewDidLoad() {
    super.viewDidLoad()
    self.navigationController?.delegate = self
}
Run Code Online (Sandbox Code Playgroud)

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

4)又符合一个方法中MyViewControllerUINavigationControllerDelegate

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


Tar*_*ras 6

在离开当前控制器之前,我需要显示警报。所以我是这样做的:

  1. 添加扩展到UINavigationControllerwithUINavigationBarDelegate
  2. 将选择器添加到您的控制器navigationShouldPopOnBack(completion:)

成功了)

extension UINavigationController: UINavigationBarDelegate {
    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        if let items = navigationBar.items, viewControllers.count < items.count {
            return true
        }

        let clientInfoVC = topViewController as? ClientInfoVC
        if clientInfoVC?.responds(to: #selector(clientInfoVC?.navigationShouldPopOnBack)) ?? false {
            clientInfoVC?.navigationShouldPopOnBack(completion: { isAllowPop in
                if isAllowPop {
                    DispatchQueue.main.async {
                        self.popViewController(animated: true)
                    }
                }
            })
        }

        DispatchQueue.main.async {
            self.popViewController(animated: true)
        }

        return false
    }
}

@objc func navigationShouldPopOnBack(completion: @escaping (Bool) -> ()) {
        let ok = UIAlertAction(title: R.string.alert.actionOk(), style: .default) { _ in
            completion(true)
        }
        let cancel = UIAlertAction(title: R.string.alert.actionCancel(), style: .cancel) { _ in
            completion(false)
        }
        let alertController = UIAlertController(title: "", message: R.string.alert.contractMessage(), preferredStyle: .alert)
        alertController.addAction(ok)
        alertController.addAction(cancel)
        present(alertController, animated: true, completion: nil)
    }
Run Code Online (Sandbox Code Playgroud)


ARS*_*LAL 5

我们的事情并不难。只需为 UIButton 创建一个具有清晰背景颜色的框架,为按钮分配操作并放置在导航栏后退按钮上。最后在使用后取下按钮。

这是使用 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)
    }
Run Code Online (Sandbox Code Playgroud)

编写需要执行的代码

func back(sender: UIBarButtonItem) {

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

    }
Run Code Online (Sandbox Code Playgroud)

执行操作后删除子视图

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

    for view in (self.navigationController?.navigationBar.subviews)!{
        if view.tag == 1 {
            view.removeFromSuperview()
        }
    }
Run Code Online (Sandbox Code Playgroud)


Ber*_*rnd 5

就我而言,viewWillDisappear效果最好。但是在某些情况下,必须修改以前的视图控制器。所以这是我的解决方案,可以访问以前的视图控制器,并且可以在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()
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)


iOS*_*iOS 5

在Swift 5和Xcode 10.2中

请不要添加自定义栏按钮项,请使用此默认行为。

不需要viewWillDisappear,不需要自定义BarButtonItem等。

最好检测何时从其父级中删除VC。

使用这两个功能中的任何一个

override func willMove(toParent parent: UIViewController?) {
    super.willMove(toParent: parent)
    if parent == nil {
        callStatusDelegate?.backButtonClicked()//Here write your code
    }
}

override func didMove(toParent parent: UIViewController?) {
    super.didMove(toParent: parent)
    if parent == nil {
        callStatusDelegate?.backButtonClicked()//Here write your code
    }
}
Run Code Online (Sandbox Code Playgroud)

如果要停止后退按钮的默认行为,则添加自定义BarButtonItem。

  • 请注意,当您以编程方式弹出时也会调用此函数,而不仅仅是按后退按钮。 (2认同)

San*_*ndu 5

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

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

    if self.isMovingFromParent {
        delegate?.passValue(clickedImage: selectedImage)
    }
}
Run Code Online (Sandbox Code Playgroud)


Hir*_*iro 5

这是我的解决方案

extension UINavigationController: UINavigationBarDelegate {
    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        if let shouldBlock = self.topViewController?.shouldPopFromNavigation() {
            return shouldBlock
        }
        return true
    }
}

extension UIViewController {
    @objc func shouldPopFromNavigation() -> Bool {
        return true
    }
}
Run Code Online (Sandbox Code Playgroud)

在您的视图控制器中,您可以这样处理:

@objc override func shouldPopFromNavigation() -> Bool {
        // Your dialog, example UIAlertViewController or whatever you want
        return false
    }
Run Code Online (Sandbox Code Playgroud)