在iOS 7中更改后退button会禁用滑动操作以导航回来

我有一个iOS 7应用程序,我在这里设置自定义后退button:

UIImage *backButtonImage = [UIImage imageNamed:@"back-button"]; UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; [backButton setImage:backButtonImage forState:UIControlStateNormal]; backButton.frame = CGRectMake(0, 0, 20, 20); [backButton addTarget:self action:@selector(popViewController) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton]; viewController.navigationItem.leftBarButtonItem = backBarButtonItem; 

但是这会禁用iOS 7的“从左向右滑动”手势以导航到前一个控制器。 有谁知道我可以如何设置自定义button,并保持这种姿态启用?

编辑:我试图设置viewController.navigationItem.backBarButtonItem,而是这似乎并不显示我的自定义图像。

重要提示:这是一个黑客。 我会build议看看这个答案 。

在分配leftBarButtonItem之后调用以下行:

 self.navigationController.interactivePopGestureRecognizer.delegate = self; 

编辑:如果在init方法中调用这不起作用。 它应该在viewDidLoad或类似的方法中调用。

如果可能的话,使用UINavigationBar的backIndicatorImage和backIndicatorTransitionMaskImage属性。 在UIAppearanceProxy上设置这些可以轻松修改应用程序中的行为。 皱纹是你只能在iOS 7上设置,但这样做,因为你只能在iOS 7上使用popup手势。 您正常的ios 6样式可以保持不变。

 UINavigationBar* appearanceNavigationBar = [UINavigationBar appearance]; //the appearanceProxy returns NO, so ask the class directly if ([[UINavigationBar class] instancesRespondToSelector:@selector(setBackIndicatorImage:)]) { appearanceNavigationBar.backIndicatorImage = [UIImage imageNamed:@"back"]; appearanceNavigationBar.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"back"]; //sets back button color appearanceNavigationBar.tintColor = [UIColor whiteColor]; }else{ //do ios 6 customization } 

试图操作interactivePopGestureRecognizer的委托将导致很多问题。

我看到这个解决schemehttp://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/它的子类UINavigationController。 它是一个更好的解决scheme,因为它处理在控制器就位之前滑动的情况 – 这会导致崩溃。

除此之外,我注意到,如果你在根视图控制器上刷一下(在推一个,然后再回来),UI变得没有反应(上面的答案也是同样的问题)。

所以在子类UINavigationController中的代码应该如下所示:

 @implementation NavigationController - (void)viewDidLoad { [super viewDidLoad]; __weak NavigationController *weakSelf = self; if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.delegate = weakSelf; self.delegate = weakSelf; } } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { // Hijack the push method to disable the gesture if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.enabled = NO; } [super pushViewController:viewController animated:animated]; } #pragma mark - UINavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { // Enable the gesture again once the new controller is shown self.interactivePopGestureRecognizer.enabled = ([self respondsToSelector:@selector(interactivePopGestureRecognizer)] && [self.viewControllers count] > 1); } @end 

我用

 [[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageNamed:@"nav_back.png"]]; [[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"nav_back.png"]]; [UIBarButtonItem.appearance setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -64) forBarMetrics:UIBarMetricsDefault]; 

我也隐藏后退button,用自定义的leftBarItem代替它。
在push操作之后删除interactivePopGestureRecognizer委托:

 [self.navigationController pushViewController:vcToPush animated:YES]; // Enabling iOS 7 screen-edge-pan-gesture for pop action if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.delegate = nil; } 
 navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self; 

这是从http://stuartkhall.com/posts/ios-7-development-tips-tricks-hacks ,但它会导致几个错误:

  1. 从屏幕左边缘滑入时,将另一个viewController推入navigationController;
  2. 或者,当从navigationControllerpopuptopViewController时,从屏幕的左边缘滑入;

例如,当导航控制器的rootViewController显示时,从屏幕的左边缘滑入,然后点击(快速)将另一个控制器推入导航控制器,然后

  • rootViewController不响应任何触摸事件;
  • anotherViewController将不会显示;
  • 再次从屏幕边缘滑动,将显示另一个控制器;
  • 点击自定义后退buttonpopupanotherViewController,崩溃!

所以你必须在self.navigationController.interactivePopGestureRecognizer.delegate实现UIGestureRecognizerDelegate方法,如下所示:

 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if (gestureRecognizer == navigationController.interactivePopGestureRecognizer) { return !navigationController.<#TODO: isPushAnimating#> && [navigationController.viewControllers count] > 1; } return YES; } 

试试self.navigationController. interactivePopGestureRecognizer .enabled = YES;

这里是尼克H247的答案 swift3版本

 class NavigationController: UINavigationController { override func viewDidLoad() { super.viewDidLoad() if responds(to: #selector(getter: interactivePopGestureRecognizer)) { interactivePopGestureRecognizer?.delegate = self delegate = self } } override func pushViewController(_ viewController: UIViewController, animated: Bool) { if responds(to: #selector(getter: interactivePopGestureRecognizer)) { interactivePopGestureRecognizer?.isEnabled = false } super.pushViewController(viewController, animated: animated) } } extension NavigationController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { interactivePopGestureRecognizer?.isEnabled = (responds(to: #selector(getter: interactivePopGestureRecognizer)) && viewControllers.count > 1) } } extension NavigationController: UIGestureRecognizerDelegate {} 

我没有写这个,但以下博客帮助了很多,并解决了自定义导航button的问题:

http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/

总之,他实现了一个使用popup手势委托的自定义UINavigationController。 很干净,便携!

码:

 @interface CBNavigationController : UINavigationController <UINavigationControllerDelegate, UIGestureRecognizerDelegate> @end @implementation CBNavigationController - (void)viewDidLoad { __weak CBNavigationController *weakSelf = self; if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.delegate = weakSelf; self.delegate = weakSelf; } } // Hijack the push method to disable the gesture - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) self.interactivePopGestureRecognizer.enabled = NO; [super pushViewController:viewController animated:animated]; } #pragma mark UINavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { // Enable the gesture again once the new controller is shown if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) self.interactivePopGestureRecognizer.enabled = YES; } 

编辑。 当用户尝试在根视图控制器上向左滑动时添加了修复问题:

 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)] && self.topViewController == [self.viewControllers firstObject] && gestureRecognizer == self.interactivePopGestureRecognizer) { return NO; } return YES; } 

我有一个类似的问题,我将当前的视图控制器分配为交互式popup手势的代表,但会破坏推送的任何视图上的手势或导航堆栈视图下方的视图。 我解决这个问题的方法是在-viewDidAppear设置委托,然后在-viewDidAppear其设置为零。 这使我的其他意见正常工作。

想象一下,我们正在使用苹果的默认主/明细项目模板,其中master是一个表视图控制器,并点击它将显示详细视图控制器。

我们要定制在详细视图控制器中出现的后退button。 这是如何自定义图像 , 图像颜色 , 文本 ,文本颜色和后退button的字体 。


要全局更改图像,图像颜色,文本颜色或字体, 请在创build任何视图控制器之前调用以下位置(例如, application:didFinishLaunchingWithOptions:是个好地方)。

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { UINavigationBar* navigationBarAppearance = [UINavigationBar appearance]; // change the back button, using default tint color navigationBarAppearance.backIndicatorImage = [UIImage imageNamed:@"back"]; navigationBarAppearance.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"back"]; // change the back button, using the color inside the original image navigationBarAppearance.backIndicatorImage = [[UIImage imageNamed:@"back"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; navigationBarAppearance.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"back"]; // change the tint color of everything in a navigation bar navigationBarAppearance.tintColor = [UIColor greenColor]; // change the font in all toolbar buttons NSDictionary *barButtonTitleTextAttributes = @{ NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Light" size:12.0], NSForegroundColorAttributeName: [UIColor purpleColor] }; [[UIBarButtonItem appearance] setTitleTextAttributes:barButtonTitleTextAttributes forState:UIControlStateNormal]; return YES; } 

请注意,您可以使用appearanceWhenContainedIn:来更好地控制哪些视图控制器受到这些更改的影响,但请记住,您无法传递[DetailViewController class] ,因为它包含在UINavigationController中,而不是您的DetailViewController。 这意味着如果您想更多地控制受影响的内容,您将需要inheritanceUINavigationController。

要自定义特定后退button项目的文本或字体/颜色,您必须在MasterViewController (而不是DetailViewController!)中执行此操作。 这看起来不直观,因为该button出现在DetailViewController上。 然而,一旦你明白了定制它的方法是通过在navigationItem上设置一个属性,它开始变得更有意义。

 - (void)viewDidLoad { // MASTER view controller [super viewDidLoad]; UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithTitle:@"Testing" style:UIBarButtonItemStylePlain target:nil action:nil]; NSDictionary *barButtonTitleTextAttributes = @{ NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Light" size:12.0], NSForegroundColorAttributeName: [UIColor purpleColor] }; [buttonItem setTitleTextAttributes:barButtonTitleTextAttributes forState:UIControlStateNormal]; self.navigationItem.backBarButtonItem = buttonItem; } 

注意:在设置self.navigationItem.backBarButtonItem后尝试设置titleTextAttributes似乎不起作用,因此必须在将值分配给此属性之前进行设置。

创build一个“UINavigationController”的子类“TTNavigationViewController”,并使这个类的现有的导航控制器在故事板/类,类示例代码 –

  class TTNavigationViewController: UINavigationController, UIGestureRecognizerDelegate { override func viewDidLoad() { super.viewDidLoad() self.setNavigationBarHidden(true, animated: false) // enable slide-back if self.responds(to: #selector(getter: UINavigationController.interactivePopGestureRecognizer)) { self.interactivePopGestureRecognizer?.isEnabled = true self.interactivePopGestureRecognizer?.delegate = self } } func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return true }}