在iOS 7中更改后退按钮将禁用滑动以向后导航

在iOS 7中更改后退按钮将禁用滑动以向后导航,ios,uinavigationcontroller,ios7,uibarbuttonitem,uiviewanimation,Ios,Uinavigationcontroller,Ios7,Uibarbuttonitem,Uiviewanimation,我有一个iOS 7应用程序,其中我设置了一个自定义后退按钮,如下所示: UIImage *backButtonImage = [UIImage imageNamed:@"back-button"]; UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; [backButton setImage:backButtonImage forState:UIControlStateNormal];

我有一个iOS 7应用程序,其中我设置了一个自定义后退按钮,如下所示:

    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;
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer == navigationController.interactivePopGestureRecognizer) {
        return !navigationController.<#TODO: isPushAnimating#> && [navigationController.viewControllers count] > 1;
    }
    return YES;
}
但这将禁用iOS 7“从左向右滑动”手势以导航到上一个控制器。有人知道我如何设置自定义按钮并保持此手势处于启用状态吗

编辑:
我尝试改为设置viewController.navigationItem.backBarButtonItem,但这似乎没有显示我的自定义图像。

尝试
self.navigationController。
.enabled=YES

重要提示: 这是一个黑客。我建议你看看这个

分配
leftBarButtonItem
后调用以下行对我有效:

self.navigationController.interactivePopGestureRecognizer.delegate = self;
[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;
}
编辑:
如果在
init
方法中调用,则此操作不起作用。应该在
viewDidLoad
或类似方法中调用它。

我还隐藏了“后退”按钮,将其替换为自定义的leftBarItem
在推送操作对我起作用后删除interactivePopGestureRecognizer委托:

self.navigationController.interactivePopGestureRecognizer.delegate = self;
[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;
}
我用

我看到了这个子类UINavigationController的解决方案。这是一个更好的解决方案,因为它可以处理在控制器就位之前刷卡的情况,这会导致崩溃

除此之外,我还注意到,如果您在根视图控制器上进行滑动(在按下一个控制器后,然后再返回),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的Backindicator图像和Backindicator TransitionMaskimage属性。在UIAppearanceProxy上设置这些选项可以轻松修改整个应用程序的行为。问题是,你只能在ios 7上设置这些,但这是可行的,因为你无论如何只能在ios 7上使用弹出手势。您正常的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
}

试图操纵InteractivePopGetureRecognizer的代理将导致许多问题。

我遇到了一个类似的问题,我将当前视图控制器指定为交互式pop手势的代理,但会在推送的任何视图或导航堆栈中视图下方的视图上打断手势。我解决这个问题的方法是在
-viewDidAppear
中设置委托,然后在
-viewwilldiscover
中将其设置为nil。这使我的其他视图能够正常工作。

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

navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
我们希望自定义显示在“详细视图”控制器中的“后退”按钮。这是如何自定义“后退”按钮的、、文本颜色和


要全局更改图像、图像颜色、文本颜色或字体,请在创建任何视图控制器之前,将以下内容放置在名为的位置(例如
应用程序:didFinishLaunchingWithOptions:
是一个好位置)

注意,您可以使用
appearancewhen contained in:
来更好地控制哪些视图控制器受到这些更改的影响,但请记住,您不能传递
[DetailViewController类]
,因为它包含在UINavigationController中,而不是您的DetailViewController中。这意味着,如果希望对受影响的内容进行更多控制,则需要将UINavigationController子类化

若要自定义特定后退按钮项的文本或字体/颜色,必须在MasterViewController(而不是DetailViewController!)中进行自定义。这似乎不直观,因为按钮出现在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后尝试设置TitleExtAttributes似乎不起作用,因此必须在将值分配给此属性之前设置它们。

我没有写这篇文章,但以下博客帮了大忙,并解决了自定义导航按钮的问题:

总之,他实现了一个自定义UINavigationController,该控制器使用pop手势委托。非常干净,便于携带

代码:


创建一个类“TTNavigationViewController”,该类是“UINavigationController”的子类,并将该类的现有导航控制器设置为故事板/类,类中的示例代码-

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

这里是swift3版本的

根视图

override func viewDidAppear(_ animated: Bool) {
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
}
儿童视图

override func viewDidLoad() {
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
} 

extension ChildViewController: UIGestureRecognizerDelegate {}

使用此逻辑保持启用或禁用滑动手势

- (void)navigationController:(UINavigationController *)navigationController
       didShowViewController:(UIViewController *)viewController
                    animated:(BOOL)animate
{
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
    {
        if (self.navigationController.viewControllers.count > 1)
        {
            self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        }
        else
        {
            self.navigationController.interactivePopGestureRecognizer.enabled = NO;
        }
    }
}

是否在视图控制器上设置此选项?还是导航控制器?我也有同样的问题,但这似乎不起作用?@mixedCase下载您的示例项目后,我现在了解您的问题。只要集合视图的内容不超过视图控制器的水平宽度,代码就可以工作。但是,一旦集合视图成为水平滚动视图,它就会覆盖InteractiveEPGEstureRecognitor。我会看看我是否能找到一个解决办法。我对这个代码有问题。它的工作时间不长,5-10回刷后VC冻结。有什么解决方案吗?Timur Bernikowich我也有同样的经历。您找到原因了吗?将委托设置为
self
会将其从类
\u UINavigationInteractiveTransition
的对象中取消设置。该对象有责任确保导航控制器在已处于转换状态时不会弹出。仍在调查在自定义“后退”按钮时是否可以启用此手势。不,它已启用。。问题似乎是它的代理不允许启动手势识别器,我在这里添加了我的解决方案作为另一个答案。中航工业能否请您解释一下为什么设置代理会起作用?我遇到了同样的问题。这种方法的一个问题是如果您在根上执行边缘平移
override func viewDidAppear(_ animated: Bool) {
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
}
override func viewDidLoad() {
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
} 

extension ChildViewController: UIGestureRecognizerDelegate {}
- (void)navigationController:(UINavigationController *)navigationController
       didShowViewController:(UIViewController *)viewController
                    animated:(BOOL)animate
{
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
    {
        if (self.navigationController.viewControllers.count > 1)
        {
            self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        }
        else
        {
            self.navigationController.interactivePopGestureRecognizer.enabled = NO;
        }
    }
}