【问题标题】:UINavigationBar TouchUINavigationBar 触控
【发布时间】:2010-01-16 10:43:24
【问题描述】:

我想在用户点击我的一个视图的导航栏标题时触发一个触摸事件。

我不知道是否可以访问 UINavigationBar 的标题视图以便将触摸事件连接到它。

这可能吗?

【问题讨论】:

    标签: ios iphone cocoa-touch uikit uinavigationbar


    【解决方案1】:

    您可以将手势识别器添加为单击导航控制器的标题。 我发现在navigationBar子视图中,标题是索引1的那个,左键的索引是0,右键的索引是2。

    UITapGestureRecognizer *navSingleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(navSingleTap)];
    navSingleTap.numberOfTapsRequired = 1;
    [[self.navigationController.navigationBar.subviews objectAtIndex:1] setUserInteractionEnabled:YES];
    [[self.navigationController.navigationBar.subviews objectAtIndex:1] addGestureRecognizer:navSingleTap];
    

    然后在您的实现中的某处实现以下内容。

    -(void)navSingleTap
    

    因此,您可以将其用于单击,或者您可以在该标题上实现您想要的任何手势识别器。

    【讨论】:

    • 如果您不想设置自定义 titleView,此方法有效。 (我没有。)
    • 是否可以设置一个色调让它看起来更像一个按钮?我试过setTintColorsetTintAdjustmentMode,但都不管用
    • 这绝对是最有效的答案。谢谢~
    • 我发现我必须把它放在viewDidLoad 方法中才能让它工作,如果我更深入地导航到情节提要并返回,否则我所有的导航栏项目都会激活它之后。
    • 嗨~@phmagic,我喜欢它只适用于topViewController,而不是secondViewController。你知道为什么吗?有人遇到同样的问题吗?
    【解决方案2】:

    我找到的解决方案是一个按钮,我使用以下(但我不知道它有多“合法”):

    UIButton *titleLabelButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [titleLabelButton setTitle:@"myTitle" forState:UIControlStateNormal];
    titleLabelButton.frame = CGRectMake(0, 0, 70, 44);
    titleLabelButton.font = [UIFont boldSystemFontOfSize:16];
    [titleLabelButton addTarget:self action:@selector(didTapTitleView:) forControlEvents:UIControlEventTouchUpInside];
    self.navigationItem.titleView = titleLabelButton;
    

    把那段代码放在你设置标题的地方。然后我在其他地方进行了测试:

    - (IBAction)didTapTitleView:(id) sender
    {
        NSLog(@"Title tap");
    }
    

    在控制台上记录了“Title Tap”!

    我处理此问题的方式可能完全错误,但可能会让您对可以查看的内容有所了解。这当然帮助了我!不过可能有更好的方法。

    【讨论】:

    • 虽然它正朝着正确的方向前进,但这很丑陋 - UIButton 的字体属性已被弃用,即使使用该属性,标题文本看起来也与正常情况大不相同。为什么要麻烦一个按钮?一个清晰的 UIView 会更好。
    • 使用 UILabel 没有错。只要确保您设置了 label.userInteractionEnabled = YES。否则,标签不会对触摸事件做出反应。
    【解决方案3】:

    其他答案都不适合我。我没有向导航栏的现有子视图添加手势或替换 titleView,而是简单地添加了一个清晰的 UIView,覆盖了导航栏的大部分......

    - (void) setupNavbarGestureRecognizer {
        // recognise taps on navigation bar to hide
        UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showHideNavbar)];
        gestureRecognizer.numberOfTapsRequired = 1;
        // create a view which covers most of the tap bar to
        // manage the gestures - if we use the navigation bar
        // it interferes with the nav buttons
        CGRect frame = CGRectMake(self.view.frame.size.width/4, 0, self.view.frame.size.width/2, 44);
        UIView *navBarTapView = [[UIView alloc] initWithFrame:frame];
        [self.navigationController.navigationBar addSubview:navBarTapView];
        navBarTapView.backgroundColor = [UIColor clearColor];
        [navBarTapView setUserInteractionEnabled:YES];
        [navBarTapView addGestureRecognizer:gestureRecognizer];
    }
    

    【讨论】:

    • 这是迄今为止唯一对我有用的,虽然我似乎需要添加:[self.navigationController.navigationBar setUserInteractionEnabled:YES];而且我仍然对按钮有干扰,因为按钮名称是我应用程序其余部分的一部分 - 有一种一致的方法可以将可触摸性附加到标题(在我的情况下是 UIImageView)
    • 啊哈,我终于得到了可以触摸的标题-方法如下:pastebin.com/eFwTShhz
    • @SamJoseph 您应该将该解决方案发布为答案
    • 这个很好,因为它不会弄乱后退按钮之类的东西。
    【解决方案4】:

    UINavigationItem 类引用有一个titleView 属性,您可以将其设置为您的自定义UIView

    换句话说,使用触摸处理程序创建UIView 的子类,然后在推送导航项时,将该项的titleView 属性设置为子类的实例。

    【讨论】:

    • 谢谢,但是我该如何操作那个触摸,例如 - 如果 titleView 被触摸,我如何在我的整体视图控制器中调用一个方法?
    • 另外,使用这种方法,我的标题属性丢失了。你能进一步解释一下吗?我添加了一个带有简单 NSLog(@"touched"); 的 touchesBegan 处理程序;但是当 titleView 被点击时它什么也不做。我正在创建子类的一个实例,并将其分配给我要推送的视图的实例,即 view.navigationItem.titleView = mySubclass;
    • 您的自定义UIView 可以有许多属性,包括用于替换标题的UILabel,以及用于“父”视图控制器的UIViewController 属性,您在创建实例时设置这些属性您的自定义视图。还要检查您的视图是否有足够大小的框架。
    【解决方案5】:

    这是 Swift 中最简单最简单的解决方案,只需复制/粘贴并填空即可:

    let navTapGesture = UITapGestureRecognizer(target: <#T##AnyObject?#>, action: <#T##Selector#>)
    navigationItem.titleView.userInteractionEnabled = true
    navigationItem.titleView.addGestureRecognizer(navTapGesture)
    

    请务必将titleView上的userInteractionEnabled设置为true,默认关闭。

    【讨论】:

    • 你好,不移除手势可以吗?
    • 当然。应该没问题。
    【解决方案6】:

    我不想将按钮指定为自定义titleView,因为这意味着我不能再使用标准标题。另一方面,在向导航栏添加点击手势识别器时,我们必须确保它不会在点击栏按钮时触发。

    此解决方案同时完成(将添加到UINavigationBar 子类):

    - (void)awakeFromNib {
        // put in -initWithFrame: if initialized manually
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ft_titleTapped:)];
        [self addGestureRecognizer:tap];
    }
    
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
        UIView *titleView = [self valueForKey:@"titleView"];
        CGRect titleFrame = titleView.frame;
        titleFrame.origin.y = 0; // expand to full height of navBar
        titleFrame.size.height = self.frame.size.height;
        return CGRectContainsPoint(titleFrame, [gestureRecognizer locationInView:self]);
    }
    
    - (void)ft_titleTapped:(UITapGestureRecognizer*)sender {
        if (sender.state == UIGestureRecognizerStateEnded) {
            // could add some checks here that the delegate is indeed a navigation controller
            UIViewController<FTViewControllerAdditions> *viewController = (id)[((UINavigationController*)self.delegate) topViewController];
            if ([viewController respondsToSelector:@selector(titleViewTapped:)]) {
                [viewController titleViewTapped:self];
            }
        }
    }
    

    它会自动向视图控制器发送-titleViewTapped: 消息(如果已实现)。在UITableViewController 子类中,您可以为滚动到顶部功能实现这样的方法:

    - (void)titleViewTapped:(id)sender {
        [self.tableView setContentOffset:CGPointMake(0, -self.tableView.contentInset.top) animated:YES];
    }
    

    注意:我们正在使用未记录的-valueForKey:@"titleView" 检索标题视图。从技术上讲,它不使用私有 API,但在未来的 iOS 版本中可能仍然会失败!

    【讨论】:

    • 这个答案对我有用,方法是在 UINavigationBar 的一个类别中覆盖 -[gestureRecognizerShouldBegin] 并将该类别导入我的视图控制器。
    【解决方案7】:

    可能的选项之一:(使用 UILabel)

    UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSomething:)];
    UILabel * titleView = [UILabel new];
    titleView.text = @"Test";
    [titleView sizeToFit];
    titleView.userInteractionEnabled = YES;
    [titleView addGestureRecognizer:tapGesture];
    
    self.navigationItem.titleView = titleView;
    

    【讨论】:

      【解决方案8】:

      这可以通过将UITapGestureRecognizer 附加到与titleView 对应的导航栏子视图来完成。

      由于 titleView 的索引根据栏按钮项的数量而变化,因此需要遍历所有导航栏子视图以找到正确的视图。

      import UIKit
      
      class ViewController: UIViewController {
      
        override func viewDidLoad() {
          super.viewDidLoad()
      
          addTitleViewTapAction("tapped", numberOfTapsRequired: 3)
        }
      
        func addTitleViewTapAction(action: Selector, numberOfTapsRequired: Int) {
      
          if let subviews = self.navigationController?.navigationBar.subviews {
            for subview in subviews {
              // the label title is a subview of UINavigationItemView
              if let _ = subview.subviews.first as? UILabel {
                let gesture = UITapGestureRecognizer(target: self, action: action)
                gesture.numberOfTapsRequired = numberOfTapsRequired
                subview.userInteractionEnabled = true
                subview.addGestureRecognizer(gesture)
                break
              }
            }
          }
        }
      
        @objc func tapped() {
      
          print("secret tap")
        }
      }
      

      【讨论】:

        【解决方案9】:

        this answerthis one 的基础上,我采用了下面的“功能”方法,我不确定它是否可读,但我更喜欢它而不是打破循环。

            if let navTitle = self.navigationController?.navigationBar.subviews.first(where: {$0.subviews.first is UILabel}) {
                let gesture = UITapGestureRecognizer(target: self, action: action)
                gesture.numberOfTapsRequired = numberOfTapsRequired
                navTitle.isUserInteractionEnabled = true
                navTitle.addGestureRecognizer(gesture)
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-15
          • 1970-01-01
          相关资源
          最近更新 更多