UINavigationController'ın geri çubuğu düğmesine basıldığında eylem yürütme


205

UINavigationControllerDüğme hala ViewControlleryığın önceki görünmesine neden olurken, bir geri düğmesine basıldığında, bir eylem (bir dizi boşaltma) yürütmek gerekiyor . Hızlı kullanarak bunu nasıl başarabilirim? resim açıklamasını buraya girin

Yanıtlar:


153

Seçeneklerden biri kendi özel geri düğmenizi uygulamak olabilir. ViewDidLoad yönteminize aşağıdaki kodu eklemeniz gerekir:

- (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];
}

GÜNCELLEME:

İşte Swift sürümü:

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

GÜNCELLEME 2:

İşte Swift 3 sürümü:

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

2
Bu, önceki görünüm denetleyicisine gelmez; kök görünüm denetleyicisine açılır.
kayalık

92
Sıradan geri düğmesi gibi bir oku nasıl alabilirim?
TomSawyer

@rocky Aşağıdaki işlevi arka işlevde deneyebilirsiniz: [self.navigationController dismissViewControllerAnimated: YES tamamlama: nil];
malajisi

2
@TomSawyer Bunun için lütfen aşağıdaki cevaba bir göz atın
fr33g

7
Bir özelliği geçersiz kılmak için bir sistem düğmesinin yerine geçmesi iyi bir yol değildir. En iyi yol aşağıdaki cevaptır! stackoverflow.com/a/27715660/2307276
dpizzuto

480

Düğmeyi başka bir yanıtta önerildiği gibi özel bir düğme ile değiştirmek, muhtemelen varsayılan davranışı ve stili kaybedeceğiniz için iyi bir fikir değildir.

Sahip olduğunuz diğer bir seçenek de ViewWillDisappear yöntemini View Controller'a uygulamak ve isMovingFromParentViewController adlı bir özelliği kontrol etmektir . Bu özellik true olursa, Görünüm Denetçisi kaldırıldığı (patlatıldığı) için kayboluyor demektir.

Şuna benzer bir şey olmalı:

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

    if self.isMovingFromParentViewController {
        // Your code...
    }
}

Hızlı 4.2

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

    if self.isMovingFromParent {
        // Your code...
    }
}

5
@gmogames evet, bunu yapamazsın. Soru buna rağmen sormadı. Geri dönme eylemini durdurabilmek için sanırım düğmeyi geçersiz kılmanız gerekiyor.
manecosta

13
For Swift 3.1 :override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if isMovingFromParentViewController { // Your code... } }
Doug Amos

23
viewWillDisappear(animated:)bir telefon çağrısı alırsanız tetiklenir. Muhtemelen istediğin bu değil. Muhtemelen kullanımı daha iyiwillMove(toParentViewController:)
Joe Susnick

Swift 4, eksik : viewWillDisappear fonk geçersiz kılma ( animasyonlu: Bool)
Javier Calatrava Llavería

1
Bu kabul edilen cevap olmalı. Temiz ve basit.
temp

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

2
Swift3 / iOS10'da çalışmıyorsa, konsol baskıları 'iç içe pop animasyon bozuk gezinme çubuğuna neden olabilir'.
itsji10dra

1
Hiç
aranmıyor

3
Bu, sadece geri giderken değil, yeni bir VC'ye taşınırken de çağrılıyor.
Jose Ramirez

@JozemiteApps yorumuna göre, görünüm denetleyicisi bir kapsayıcı görünüm denetleyicisine eklenmeden veya bu denetleyiciden kaldırılmadan hemen önce çağrılan dokümanlardır . .
nstein

2
Bu kabul edilen cevap olmalı. Ve ne zaman parent == niltaşınıyoruz zaman sırtını için parentolay yerine
Sylvan D Ash

32

Bunu aşağıdakilerle başardım:

Hızlı 3

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

   if parent == nil {
      println("Back Button pressed.")
      delegate?.goingBack()
   }           
}

Hızlı 4

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

    if parent == nil {
        debugPrint("Back Button pressed.")
    }
}

Özel geri düğmesine gerek yok.


Bu fantastik. Eski açıklama ama yine de en son Swift ile çalışıyor.
user3204765

Bu, bir sonraki görünüm denetleyicisinden (bunun üzerinde) çözüldüğünde de tetiklenir (yanlış pozitif), bu yüzden gerçekten geri düğmesine basma algılaması olmaz.
user2878850

Önceki kişiyle aynı açıklamada, bu kod geri düğmesinin etkinleştirildiğini değil, geçerli görünümün pop'unu algılar.
Vilmir

31

Geri ok da dahil olmak üzere normal bir geri düğmesi oluşturmak için bu (swift) sınıfı oluşturdum. Normal metin veya resim içeren bir düğme oluşturabilir.

kullanım

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 eklentisi ile oluşturulan geri oku çizme kodu)

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

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

İOS 11 için yanıtınızı güncellemek çok nazik misiniz?
BR41N-FCK

2
Merhaba @guido, çözümünüz mükemmel, kodunuzu denedim ve negatif genişlikte barbutton ekleseniz bile geri düğmesinin önünde boşluk olduğunu fark ettim.
Pawriwes

26

Geri oklu geri düğmesine sahip olmak istiyorsanız, aşağıdaki resmi ve kodu kullanabilirsiniz

backArrow.png arrow1backArrow@2x.png Arrow2backArrow@3x.pngarrow3

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

12

Kullanıyorsanız navigationController, UINavigationControllerDelegateprotokolü sınıfa ekleyin ve temsilci yöntemini aşağıdaki gibi ekleyin:

class ViewController:UINavigationControllerDelegate {

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

Bu yöntem, gezinti denetleyicisi her yeni ekrana kaydırıldığında çağrılır. Geri düğmesine basılırsa, yeni görünüm denetleyicisinin ViewControllerkendisi olur.


Delege olarak bir NSObjectProtocol sınıfı kullanırken korkunç olur.
Nick Weaver

Geri düğmesine basıldığında her zaman çağrılmaz.
Ted

10

Swift 5 ve Xcode 10.2'de

Lütfen özel çubuk düğmesi öğesi eklemeyin, bu varsayılan davranışı kullanın.

Gerek yok viewWillDisappear , gerek özel BarButtonItem vs ...

VC'nin üst öğesinden ne zaman kaldırıldığını tespit etmek daha iyidir.

Bu iki işlevden herhangi birini kullanın

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

Geri düğmesinin varsayılan davranışını durdurmak istiyorsanız, özel BarButtonItem ekleyin.


1
Bunun, yalnızca geri düğmesine basmakla kalmayıp, programlı olarak açtığınızda da çağrıldığını unutmayın.
Ixx

7

HAYIR

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

Bu segueing bile denilen alacak için bu yöntemi geçersiz olduğu görünümü denetleyicisi. Hangi " parent" nilolup olmadığını kontrol edin doğru geri hareket emin olmak için kesin bir yol değildir UIViewController. Tam olarak bu geçerli UINavigationControllerolana geri dönüp UIViewControllerdönmediğini belirlemek için UINavigationControllerDelegateprotokole uymanız gerekir .

EVET

not: geri dönmek istediğiniz MyViewControllerher şeyin adıdır UIViewController.

1) Dosyanızın en üstüne ekleyin UINavigationControllerDelegate.

class MyViewController: UIViewController, UINavigationControllerDelegate {

2) Sınıfınıza UIViewController, aradığınız şeyi takip edecek bir özellik ekleyin .

class MyViewController: UIViewController, UINavigationControllerDelegate {

var previousViewController:UIViewController

3) MyViewController'in viewDidLoadyönteminde selfsizin için delege olarak atayın UINavigationController.

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

3) Segue etmeden önce öncekiniUIViewController bu özellik olarak atayın .

// 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) ve bir yönteme uygun MyViewControllerbirUINavigationControllerDelegate

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

1
Yararlı cevap için teşekkürler! Okuyucular UINavigationController temsilcisini belirli bir görünüm denetleyicisine ayarlamaya dikkat eder; gezinti denetleyicisinde zaten bir temsilci varsa, diğer geri arama temsilcisini beklemekten mahrum kalma riskiyle karşı karşıya kalırsınız. Bizim app, UINavigationController delegesi tüm görünüm denetleyicilerinin bir işaretçi sahip paylaşılan bir nesnedir (bir AppCoordinator).
Bill Feth

7

Benim durumumda en viewWillDisappeariyi çalıştı. Ancak bazı durumlarda önceki görünüm denetleyicisini değiştirmek gerekir. İşte önceki görünüm denetleyicisine erişimi olan çözümüm ve Swift 4'te çalışıyor :

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

-viewDidDisappear (veya -viewWillDisappear), görünüm başka bir görünüm denetleyicisinin görünümü tarafından kaplansa bile (yalnızca <Geri düğmesine basıldığında değil) çağrılır, bu nedenle isMovingFromParentViewController öğesini kontrol etme ihtiyacı vardır.
Bill Feth

5

Mevcut denetleyiciden ayrılmadan önce uyarı göstermem gerekiyor. Bu şekilde yaptım:

  1. Uzantısı ekle UINavigationControllerileUINavigationBarDelegate
  2. Seçiciyi denetleyicinizin gezinmesine ekleyinShouldPopOnBack (tamamlanma :)

Çalıştı)

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

4

Bizim gibi zor değil. Açık arka plan rengine sahip UIButton için bir çerçeve oluşturun, düğme için eylem atayın ve gezinme çubuğu geri düğmesinin üzerine yerleştirin. Ve son olarak kullanımdan sonra düğmeyi çıkarın.

İşte UIButton yerine UIImage ile yapılan Swift 3 örnek kodu

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

yürütülecek kodu yaz

func back(sender: UIBarButtonItem) {

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

    }

Eylem gerçekleştirildikten sonra subView'i kaldırın

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

    for view in (self.navigationController?.navigationBar.subviews)!{
        if view.tag == 1 {
            view.removeFromSuperview()
        }
    }

Tesekkurler dostum . :-)
ARSHWIN DENUEV LAL

Aşağı dokunduğunuzda durumu nasıl yaratırsınız?
quang thang

Bu, iOS 11'de çalışmıyor gibi görünüyor. UIImageView'ın arka plan rengi açık olduğunda değil. Farklı bir renge ayarlayın ve işe yarıyor.
Dokunma Formları

Açık renkli bir UIImageView tanımlayabilir, çerçevesini ayarlayabilir, tapgesture atayabilir ve ekranın herhangi bir yerine yerleştirebiliriz. Öyleyse neden bir gezinti çubuğunun üzerine yerleştiremiyoruz. Samimi olmak için yazdıklarımı tavsiye etmeyeceğim. Bir sorun varsa kesinlikle bir sebep var ama renk önemli değil. Kodu unutma u başarılı olacak mantığı izleyin. :)
ARSHWIN DENUEV LAL

4

Hızlı 4.2:

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

    if self.isMovingFromParent {
        // Your code...

    }
}

3

Hızlı 3:

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

    if parent == nil{
        print("Back button was clicked")
    }
}

-did / willMove (toParentViewController :) muhtemelen -viewWillDisappear içinde isMovingTfromParentViewController öğesini denetlemekten daha iyidir, çünkü yalnızca görünüm denetleyicisi aslında ebeveynleri değiştirirken çağrılır (görünüm başka bir VC'nin görünümü kapsamında olduğunda değil) UINavigationController delege yöntemini uygulamak için. Yine de dikkatli olun; NavigationController'da zaten bir temsilci varsa, diğer geri arama temsilcisini beklemekten mahrum kalma riskiyle karşı karşıya kalırsınız.
Bill Feth

Bir splitViewController ile test ettim. Orada, eklenen veya kaldırılanlar arasındaki fark yaratılamadı.
claude31

2

Bunu dene .

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

Bunu da deneyin.

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

2

sadece kontrol + çubuk öğesi fonk altında sürükleyin. çekicilik gibi çalışmak

@IBAction func done(sender: AnyObject) {
    if((self.presentingViewController) != nil){
        self.dismiss(animated: false, completion: nil)
        print("done")
    }
}

resim açıklamasını buraya girin


2

Alt sınıflandırabilir UINavigationControllerve geçersiz kılabilirsiniz popViewController(animated: Bool). Orada bazı kodları yürütmenin yanı sıra, örneğin mevcut çalışmasını kaydetme veya atma istemi için kullanıcının tamamen geri gitmesini de önleyebilirsiniz.

popHandlerİtilen denetleyiciler tarafından ayarlanan / silinen bir ayarlayabileceğiniz örnek uygulama .

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

Kaydedilmemiş işleri izleyen bir itmeli kumandadan örnek kullanım.

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

Hoş bir dokunuş olarak, interactivePopGestureRecognizerkullanıcı bir kaydırma hareketi kullanarak geri dönmeye çalıştığında da çağrılacaktır .


üstün cevap, Teşekkürler Rivera
DvixExtract

2

Bu benim çözümüm

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

Görünüm denetleyicinizde şu şekilde çalışabilirsiniz:

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

1

Sana boşaltmak istiyorum anlamak gibi arraysize geri düğmesine basın olarak ve önceki etmek pop ViewController letsenin Arraybu ekran üzerinde size yüklenen hangi

let settingArray  = NSMutableArray()
@IBAction func Back(sender: AnyObject) {
    self. settingArray.removeAllObjects()
    self.dismissViewControllerAnimated(true, completion: nil)
} 

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

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

    if self.isMovingToParent {

        //your code backView
    }
}

1

For Swift 5 , biz kaybolur görünümünde kontrol edebilirsiniz

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

    if self.isMovingFromParent {
        delegate?.passValue(clickedImage: selectedImage)
    }
}

1

Swift 5 __ Xcode 11.5

Benim durumumda bir animasyon yapmak istedim ve bittiğinde geri dönün. Geri düğmesinin varsayılan eyleminin üzerine yazmanın ve özel işleminizi çağırmanın bir yolu şudur:

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

Gezinti Çubuğu görünüm hiyerarşisi

Veya bu yöntemi bir kez kullanarak NavigationBar görünüm hiyerarşisini keşfedebilir ve dizinlerin _UIButtonBarButton görünümüne erişmesini, UIControl'e yayınlanmasını, hedef eylemini kaldırmasını ve özel hedef eylemlerinizi eklemesini sağlayabilirsiniz:

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

0

Bu çağrı / geçersiz kılma viewWillDisappearve daha sonra navigationControllerbenzer yığını erişerek başardı :

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

0

Kendi sorunum için böyle çözdüm

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationItem.leftBarButtonItem?.action = #selector(self.back(sender:))
    self.navigationItem.leftBarButtonItem?.target = self
}

@objc func back(sender: UIBarButtonItem) {

}

0

Özel bir geri düğmesi oluşturmanızı ve tüm aldığınız tüm UINavigationController sol düğme işlevlerinden vazgeçmenizi gerektirmeyen mümkün olan en basit Swift 5 çözümü.

As Brandon A yukarıda önerir uygulamak gerekir gerek UINavigationControllerDelegateona dönmeden önce etkileşimde istediğiniz görünümü kumandam. İyi bir yol, manuel veya otomatik olarak gerçekleştirebileceğiniz ve aynı kodu özel yapılmış bir düğmeden veya geri düğmesinden yeniden kullanabileceğiniz bir gevşeme sekmesi oluşturmaktır.

İlk olarak, görünüm denetleyicinizi (geri döndüğünü tespit etmek istediğiniz) ilgilendiren gezinme denetleyicisinin temsilcisini şurada yapın viewDidLoad:

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

İkinci olarak, dosyanın altına geçersiz kılan bir uzantı ekleyin navigationController(willShow:animated:)

extension PickerTableViewController: UINavigationControllerDelegate {

    func navigationController(_ navigationController: UINavigationController,
                              willShow viewController: UIViewController,
                              animated: Bool) {

        if let _ = viewController as? EditComicBookViewController {

            let selectedItemRow = itemList.firstIndex(of: selectedItemName)
            selectedItemIndex = IndexPath(row: selectedItemRow!, section: 0)

            if let selectedCell = tableView.cellForRow(at: selectedItemIndex) {
                performSegue(withIdentifier: "PickedItem", sender: selectedCell)
            }
        }
    }
}

Sorunuz a'yı UITableViewControlleriçerdiğinden, kullanıcının dokunduğu satırın dizin yolunu almanın bir yolunu ekledim.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.