检测长按 UINavigationItem 的后退按钮

Posted

技术标签:

【中文标题】检测长按 UINavigationItem 的后退按钮【英文标题】:detect long press on UINavigationItem's back button 【发布时间】:2011-06-28 15:41:58 【问题描述】:

我想通过基于 UINavigationController 的应用程序向我的后退按钮添加功能,其中长按后退按钮将弹出到根目录。但是,我不知道在哪里附加手势识别器。我是否继承 UINavigationBar 并尝试检测长按是否在左键区域?

我之前听说有人添加了类似的功能。有人有什么想法吗?

【问题讨论】:

【参考方案1】:

我知道这个问题很老,但我想出了一个解决方案。我没有尝试将手势识别器添加到按钮本身(这将是理想的),而是将其添加到self.navigationController.navigationBar,然后在操作方法中,使用locationInView 来查看我是否超过了后退按钮。我不完全确定如何精确地识别后退按钮,所以我笨拙地抓住了第一个 x 坐标小于某个任意值的子视图,但这似乎很有希望。如果有人有更好的方法来识别后退按钮的框架,请告诉我。

- (void)longPress:(UILongPressGestureRecognizer *)sender 

    if (sender.state == UIGestureRecognizerStateEnded)
    
        // set a default rectangle in case we don't find the back button for some reason

        CGRect rect = CGRectMake(0, 0, 100, 40);

        // iterate through the subviews looking for something that looks like it might be the right location to be the back button

        for (UIView *subview in self.navigationController.navigationBar.subviews)
        
            if (subview.frame.origin.x < 30) 
            
                rect = subview.frame;
                break;
            
        

        // ok, let's get the point of the long press

        CGPoint longPressPoint = [sender locationInView:self.navigationController.navigationBar];

        // if the long press point in the rectangle then do whatever

        if (CGRectContainsPoint(rect, longPressPoint))
            [self doWhatever];
    


- (void)addLongPressGesture

    if (NSClassFromString(@"UILongPressGestureRecognizer"))
    
        UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
        [self.navigationController.navigationBar addGestureRecognizer:longPress];
        [longPress release];
    

【讨论】:

好主意。下次我需要这样做时,我会尝试你的方法。感谢您的跟进! 我可以长按那里弹出 - 对我来说似乎很合理。 我有同样的要求,比如在后退按钮上设置一个 longPress 手势。这种方法的问题是后退按钮不会保持突出显示状态。所以我将 cancelsTouchesInView 属性设置为 NO.BUt然后我的 longPressHandler 和 backButton 处理程序都被调用了。有什么解决方案吗?? @user1010819 不,我什么也没有。不过,老实说,如果我今天要解决这个问题,我无疑不会使用这个技巧来向标准导航控制器添加长按手势(因为最终用户在标准 UI 控件上使用自定义行为就像标准导航栏)。我会用我自己的看起来不同的图形按钮替换后退按钮(让用户知道这个应用程序的工作方式不同),可能用我自己的自定义容器类替换整个导航控制器和栏。 嗯。我做了同样的事情。但是使用自定义后退按钮会与交互式弹出手势混淆。在浪费了 2-3 天后,我无法找到合适的工作解决方案,所以我继续这样做,我找到了解决方法问题的方法。为了防止 backBarButtonItem 操作处理程序执行,我在 UILongPressGestureRecognizerStateEnded 中将 cancelsTouchesInView 设置为 YES。这有效。【参考方案2】:

我相信 UIGestureRecognizers 只能添加到 UIViews 和 UIViews 的子类中。

http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html

后退按钮是一个 UIBarButtonItem,它继承自 NSObject。因此,您将无法使用

将手势识别器附加到标准后退按钮
UILongPressGestureRecognizer *longPressGesture =
            [[[UILongPressGestureRecognizer alloc]
              initWithTarget:self action:@selector(longPress:)] autorelease];

[self.navigationItem.backBarButtonItem addGestureRecognizer:longPressGesture];

但是,您可以将自定义视图添加到 UIBarButtonItem。自定义视图可以很容易地成为 UIView、UIButton、UILabel 等。

例子:

UIView *myTransparentGestureView = [[UIView alloc] initWithFrame:CGRectMake(0,0,40,30)];
[myTransparentGestureView addGestureRecognizer:longPressGesture];
[self.navigationItem.backBarButtonItem setCustomView:myTransparentGestureView];
// Or you could set it like this
// self.navigationItem.backBarButtonItem.customView = myTransparentGestureView;
[myTransparentGestureView release];

但是,您必须小心,因为在 backBarButtonItem 上设置属性适用于您推送的下一个视图。因此,如果您有视图 A 推送到视图 B,并且您希望在视图 B 中点击返回时识别手势。您必须在视图 A 中进行设置。

【讨论】:

将手势识别器添加到 backButtomItem 上的自定义视图对我不起作用...识别器拒绝触发。你能用上面的代码让它工作吗? 它可能不起作用,因为 backBarButtonItem 是只读的,因此它不接受自定义视图。您很可能需要像这个答案一样创建自己的 leftbarbuttonitem 。 ***.com/questions/526520/… 啊,但是除非我找到图像,否则我会丢失我的后退箭头......可能不值得。不过还是谢谢!【参考方案3】:

我走的是一条略有不同的道路,我想我会分享它。上面的答案很好,但实际上,如果长按在导航栏的前 1/3 处,那对我来说已经足够了:

- (void)longPress:(UILongPressGestureRecognizer *)gr

    NSLog(@"longPress:");
    UINavigationBar *navBar = [self navigationBar];
    CGFloat height = navBar.bounds.size.height;
    CGPoint pt = [gr locationOfTouch:0 inView:navBar];
    //NSLog(@"PT=%@ height=%f", NSStringFromCGPoint(pt), height);
    if(CGRectContainsPoint(CGRectMake(0,0,100,height), pt)) 
        [self popToViewController:self.viewControllers[0] animated:YES];
    

【讨论】:

【参考方案4】:

这是我的解决方案:

在 appDelegate(我的应用中导航栏的“所有者”)中,在 applicationDidFinishLaunchingWithOptions 中:

获取导航栏视图并将手势识别器添加到整个视图:

// Get the nav bar view
UINavigationBar *myNavBar = nil;
for (UIView *view in [self.window.rootViewController.view subviews]) 
    if ([view isKindOfClass:[UINavigationBar class]]) 
        NSLog(@"Found Nav Bar!!!");
        myNavBar = (UINavigationBar *)view;
    


UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self
                                                                                        action:@selector(backButtonLongPress:)];
[myNavBar addGestureRecognizer:longPress];
NSLog(@"Gesture Recognizer Added.");

然后在appDelegate中,在-(void) backButtonLongPress:(id) sender

检查手势是否出现在后退按钮的框架内:

if ([sender state] == UIGestureRecognizerStateBegan) 

    // Get the nav bar view
    UINavigationBar *myNavBar = nil;
    for (UIView *view in [self.window.rootViewController.view subviews]) 
        if ([view isKindOfClass:[UINavigationBar class]]) 
            NSLog(@"Found Nav Bar!!!");
            myNavBar = (UINavigationBar *)view;
        
    

    // Get the back button view
    UIView *backButtonView = nil;
    for (UIView *view in [myNavBar subviews]) 
        if ([[[view class] description] isEqualToString:@"UINavigationItemButtonView"]) 
            backButtonView = view;
            NSLog(@"Found It: %@", backButtonView);
            NSLog(@"Back Button View Frame: %f, %f; %f, %f", backButtonView.frame.origin.x, backButtonView.frame.origin.y, backButtonView.frame.size.width, backButtonView.frame.size.height);
        
    

    CGPoint longPressPoint = [sender locationInView:myNavBar];
    NSLog(@"Touch is in back button: %@", CGRectContainsPoint(backButtonView.frame, longPressPoint) ? @"YES" : @"NO");
    if (CGRectContainsPoint(backButtonView.frame, longPressPoint)) 
        // Place your action here
    

    // Do nothing if outside the back button frame


【讨论】:

以上是关于检测长按 UINavigationItem 的后退按钮的主要内容,如果未能解决你的问题,请参考以下文章

设置 uinavigationitem 的后退按钮不起作用

UINavigationItem 后退按钮返回到上一个导航项,但视图没有改变

UINavigationItem:检测触摸

如何更改 UINavigationItem 的背景颜色?

使用 UINavigationItem 类的属性 leftItemsSupplementBackButton

UINavigationItem 标题视图的框架