替换后退按钮但保持滑动以导航回来

时间:2016-07-04 07:41:29

标签: ios swift uinavigationcontroller

首先,我注意到有一个similar question。但是,我想问一下Swift中的解决方案。这是我的代码:

override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Button", style: .Plain, target: self, action: nil)
}

我想要更换后退按钮,但要保持滑动以便用户导航回来。但是,这会禁用滑动。我无法在上面的链接中获得已接受的答案和建议的答案。这是我试图翻译成Swift的内容。

let appearanceNavigationBar = UINavigationBar.appearance()
appearanceNavigationBar.backIndicatorImage = UIImage(named: "back")
appearanceNavigationBar.backIndicatorTransitionMaskImage = UIImage(named: "back")
appearanceNavigationBar.tintColor = UIColor.whiteColor()

我正在使用Xcode 8.0 beta,Swift 2.3并在iOS 10.0中进行测试。任何帮助将不胜感激。

5 个答案:

答案 0 :(得分:7)

我用过它并且有效:

self.navigationController.interactivePopGestureRecognizer.delegate = nil;

答案 1 :(得分:1)

接受的答案不完整。如果您配置了情节提要剧情,并且在第一个视图控制器上尝试“向后滑动”手势,则可能无法触发该情节。

将所有极端情况都考虑在内的最佳解决方案是:

class QFNavigationController:UINavigationController, UIGestureRecognizerDelegate, UINavigationControllerDelegate{
    override func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
        delegate = self
    }

    override func pushViewController(_ viewController: UIViewController, animated: Bool) {
        super.pushViewController(viewController, animated: animated)
        interactivePopGestureRecognizer?.isEnabled = false
    }

    func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
        interactivePopGestureRecognizer?.isEnabled = true
    }

    // IMPORTANT: without this if you attempt swipe on
    // first view controller you may be unable to push the next one
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }

}

现在只需在需要时使用QFNavigationController

答案 2 :(得分:0)

this answer中所述将委托设置为nil会导致iOS 11中出现一些令人讨厌的错误,例如this one

但是,对代表进行存根的想法总的来说是好的。例如,您可以编写以下代码

final class NavigationController: UINavigationController {
    private var customDelegate: InteractivePopGestureRecognizerDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()

        customDelegate = InteractivePopGestureRecognizerDelegate(
            originalDelegate: interactivePopGestureRecognizer?.delegate,
            navigationController: self
        ) 
        interactivePopGestureRecognizer?.delegate = customDelegate
    }
}

然后,您可以使用自定义委托来解决问题的根本原因

final class InteractivePopGestureRecognizerDelegate:
    NSObject,
    UIGestureRecognizerDelegate
{
    private weak var originalDelegate: UIGestureRecognizerDelegate?
    private weak var navigationController: UINavigationController?

    init(
        originalDelegate: UIGestureRecognizerDelegate?,
        navigationController: UINavigationController)
    {
        self.originalDelegate = originalDelegate
        self.navigationController = navigationController
    }

    func gestureRecognizer(
        _ gestureRecognizer: UIGestureRecognizer,
        shouldReceive touch: UITouch)
        -> Bool
    {
        if let originalDelegate = originalDelegate,
            let result = originalDelegate.gestureRecognizer?(
                gestureRecognizer,
                shouldReceive: touch)
        {
            if !result {
                // Your interactive pop gesture got cancelled here

                // Perform sanity check of pop possibility
                if (navigationController?.viewControllers.count ?? 0) < 2 {
                    return result
                }

                if navigationController?.navigationBar.isHidden == true {
                    // Return true here if you want to swipe even without navigation bar
                    return result
                }

                // Enable pop gesture
                return true
            }
        } else {
            return true
        }
    }

    ...
    // Proxy all other `UIGestureRecognizerDelegate` methods to the originalDelegate here
    ...
}

当然这有点棘手,未来可能无法工作(像其他任何黑客一样)

答案 3 :(得分:0)

好吧,所以3年过去了,您可能不再需要解决此问题的方法:)但这可能会帮助其他人解决此问题。这实际上非常简单:您只需要配置后退按钮,该按钮将在第一个视图控制器的第二个视图控制器上显示。这是一个示例:

class FirstViewController: UIViewController {
  override func viewDidLoad() {
    let backButton = UIBarButtonItem(image: UIImage(systemName: "chevron.left.circle.fill"), style: .done, target: nil, action: nil)
    navigationItem.backBarButtonItem = backButton
  }

  func presentSecondViewController() {
    navigationController?.pushViewController(SecondViewController(), animated: true)
  }
}

以这种方式配置FirstViewController将允许您在SecondViewController上显示自定义后退按钮,并保持向后滑动手势。

答案 4 :(得分:-4)

您可以从StoryBoard设置所有这些。转到导航控制器中的“属性检查器”导航栏。