ios 识别点击导航栏标题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26287322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:06:57  来源:igfitidea点击:

Recognize tap on navigation bar title

iosswiftuinavigationcontrolleruitapgesturerecognizer

提问by Richard

Could someone please help me recognise a tap when a user taps on the Titlein the Navigation Bar?

可能有人请帮助我认识一个水龙头时,在用户点击标题导航栏

I would like to recognise this tap and then animate the tableHeaderViewappearing. Possibly sliding the TableView down.

我想识别这个点击,然后为出现的tableHeaderView设置动画。可能向下滑动 TableView。

The idea being that the user can then select a quick option (from the tableViewHeader) to re-populate the TableView.

这个想法是用户可以选择一个快速选项(从 tableViewHeader)来重新填充 TableView。

However I cannot recognise any taps.

但是我无法识别任何水龙头。

I'm using Swift.

我正在使用斯威夫特。

Thank you.

谢谢你。

回答by rob mayoff

UINavigationBardoes not expose its internal view hierarchy. There is no supported way to get a reference to the UILabelthat displays the title.

UINavigationBar不公开其内部视图层次结构。不支持获取对UILabel显示标题的引用的方法。

You could root around in its view hierarchy “manually” (by searching through its subviews), but that might stop working in a future iOS release because the view hierarchy is private.

您可以“手动”(通过搜索它的subviews)在其视图层次结构中扎根,但这可能会在未来的 iOS 版本中停止工作,因为视图层次结构是私有的。

One workaround is to create a UILabeland set it as your view controller's navigationItem.titleView. It's up to you to match the style of the default label, which may change in different versions of iOS.

一种解决方法是创建一个UILabel并将其设置为您的视图控制器的navigationItem.titleView. 由您来匹配默认标签的样式,在不同的 iOS 版本中可能会发生变化。

That said, it's pretty easy to set up:

也就是说,它很容易设置:

override func didMove(toParentViewController parent: UIViewController?) {
    super.didMove(toParentViewController: parent)

    if parent != nil && self.navigationItem.titleView == nil {
        initNavigationItemTitleView()
    }
}

private func initNavigationItemTitleView() {
    let titleView = UILabel()
    titleView.text = "Hello World"
    titleView.font = UIFont(name: "HelveticaNeue-Medium", size: 17)
    let width = titleView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)).width
    titleView.frame = CGRect(origin:CGPoint.zero, size:CGSize(width: width, height: 500))
    self.navigationItem.titleView = titleView

    let recognizer = UITapGestureRecognizer(target: self, action: #selector(YourViewController.titleWasTapped))
    titleView.userInteractionEnabled = true
    titleView.addGestureRecognizer(recognizer)
}

@objc private func titleWasTapped() {
    NSLog("Hello, titleWasTapped!")
}

I'm setting the size of the label to its natural width (using sizeThatFits:), but I'm setting its height to 500. The navigation bar will keep the width but shrink the height to the bar's own height. This maximizes the area available for tapping (since the natural height of the label might be only ~22 points but the bar is 44 points high).

我将标签的大小设置为其自然宽度(使用sizeThatFits:),但我将其高度设置为 500。导航栏将保持宽度但将高度缩小到栏自身的高度。这最大化了可用于点击的区域(因为标签的自然高度可能只有 ~22 点,但条形有 44 点高)。

回答by Zia

From the answers, we can tell there are two approaches to do this.

从答案中,我们可以看出有两种方法可以做到这一点。

  1. Add a UITapGestureRecognizerto the titleView. This does not seem elegant and requires you to manually set the navigation bar title font so I would not recommend it.
  2. Add a UITapGestureRecognizerto the navigationBar. This seems pretty elegant but the problem with the posted answers that take this approach is that they all result in preventing controls within the navigation bar from working. Here is my implementation of this method that allows your controls to continue working.
  1. 添加一个UITapGestureRecognizertitleView. 这看起来不太优雅,需要您手动设置导航栏标题字体,因此我不推荐它。
  2. 添加一个UITapGestureRecognizernavigationBar. 这看起来很优雅,但采用这种方法的已发布答案的问题在于它们都会导致导航栏中的控件无法工作。这是我对这种方法的实现,它允许您的控件继续工作。


// Declare gesture recognizer
var tapGestureRecognizer: UITapGestureRecognizer!

override func viewDidLoad() {

    // Instantiate gesture recognizer
    tapGestureRecognizer = UITapGestureRecognizer(target:self, action: #selector(self.navigationBarTapped(_:)))
}

override func viewWillAppear(_ animated: Bool) {

    // Add gesture recognizer to the navigation bar when the view is about to appear
    self.navigationController?.navigationBar.addGestureRecognizer(tapGestureRecognizer)

    // This allows controlls in the navigation bar to continue receiving touches
    tapGestureRecognizer.cancelsTouchesInView = false
}

override func viewWillDisappear(_ animated: Bool) {

    // Remove gesture recognizer from navigation bar when view is about to disappear
    self.navigationController?.navigationBar.removeGestureRecognizer(tapGestureRecognizer)
}

// Action called when navigation bar is tapped anywhere
@objc func navigationBarTapped(_ sender: UITapGestureRecognizer){

    // Make sure that a button is not tapped.
    let location = sender.location(in: self.navigationController?.navigationBar)
    let hitView = self.navigationController?.navigationBar.hitTest(location, with: nil)

    guard !(hitView is UIControl) else { return }

    // Here, we know that the user wanted to tap the navigation bar and not a control inside it 
    print("Navigation bar tapped")

}

回答by Steve Rosenberg

This is a solution, albeit not super elegant. In the storyboard just place a regular UIButton over the title and attach it to an IBAction in your ViewController. You may need to do this for each view.

这是一个解决方案,虽然不是超级优雅。在故事板中,只需在标题上放置一个常规 UIButton 并将其附加到您的 ViewController 中的 IBAction。您可能需要为每个视图执行此操作。

回答by megaBreezy

Bruno's answer was 90% there for me. One thing I noted, though, was that UIBarButtonItem functionality for the Navigation Controller stopped working in other View Controllers, once this gesture recognizer was added to it. To fix this, I just remove the gesture from the Navigation Controller when the view is preparing to disappear:

布鲁诺的回答对我来说是 90%。不过,我注意到的一件事是,导航控制器的 UIBarButtonItem 功能在其他视图控制器中停止工作,一旦添加了这个手势识别器。为了解决这个问题,我只是在视图准备消失时从导航控制器中删除手势:

var tapGestureRecognizer : UITapGestureRecognizer!

override func viewWillAppear(_ animated: Bool) {

  tapGestureRecognizer = UITapGestureRecognizer(target:self, action: #selector(self.navBarTapped(_:)))

  self.navigationController?.navigationBar.addGestureRecognizer(tapGestureRecognizer)

}

override func viewWillDisappear(_ animated: Bool) {

  self.navigationController?.navigationBar.removeGestureRecognizer(tapGestureRecognizer)

}

func navBarTapped(_ theObject: AnyObject){

  print("Hey there")

}

回答by Bruno Cunha

A simple approach may be just creating the tap gesture recognizer and attaching it to your navigation bar element.

一种简单的方法可能只是创建点击手势识别器并将其附加到您的导航栏元素。

// on viewDidLoad
let tapGestureRecognizer = UITapGestureRecognizer(target:self, action: #selector(YourViewController.somethingWasTapped(_:)))
self.navigationController?.navigationBar.addGestureRecognizer(tapGestureRecognizer)

func somethingWasTapped(_ sth: AnyObject){
    print("Hey there")
}

回答by James Andrews

There is a simpler and more elegant solution using gesture recognisers (at least for iOS 9 and above).

使用手势识别器有一个更简单、更优雅的解决方案(至少对于 iOS 9 及更高版本)。

UITapGestureRecognizer * titleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(titleTapped)];
[self.navigationItem.titleView addGestureRecognizer:titleTapRecognizer];

Then add the title tapped method:

然后添加标题 tapped 方法:

-(void) titleTapped {
    // Called when title is tapped
}

回答by Mahmut C

Regarding navigationItem.titleViewis a UIViewindeed, I ended up using a UIButtonwhich gives all the flexibility out-of-box.

关于navigationItem.titleViewis aUIView确实,我最终使用了 a UIButton,它提供了开箱即用的所有灵活性。

override func viewDidLoad() {

    // Create title button
    let titleViewButton = UIButton(type: .system)
    titleViewButton.setTitleColor(UIColor.black, for: .normal)
    titleViewButton.setTitle("Tap Me", for: .normal)

    // Create action listener
    titleViewButton.addTarget(self, action: #selector(YourViewController.titleViewButtonDidTap), for: .touchUpInside)

    // Set the title view with newly created button
    navigationItem.titleView = titleViewButton
}

@objc func titleViewButtonDidTap(_ sender: Any) {
    print("Title did tap")
}

回答by WholeCheese

Zia: Your guard !(hitView is UIControl)solution has been working well for me while running under iOS 9 but when I run the same code in newer iOS versions it fails to see the hitView as a UIControl when the tapped barButton is disabled.

Zia:您的guard !(hitView is UIControl)解决方案在 iOS 9 下运行时对我来说效果很好,但是当我在较新的 iOS 版本中运行相同的代码时,当点击的 barButton 被禁用时,它无法将 hitView 视为 UIControl。

I have a number of UIBarButtonItems in my navigation bar. When these barButtons are enabled the (hitView is UIControl) in my UITapGestureRecognizer action works correctly and the action function exits. But if the UIBarButtonItem is disabled and the user taps on the button, the (hitView is UIControl)is false and the code proceeds as if the user has tapped the navigation bar.

我的导航栏中有许多 UIBarButtonItems。当这些 barButton 被启用时,我的 UITapGestureRecognizer 动作中的(hitView 是 UIControl)可以正常工作并且动作函数退出。但是如果 UIBarButtonItem 被禁用并且用户点击按钮,(hitView is UIControl)则为 false 并且代码继续执行,就像用户点击导航栏一样。

The only way I have found to work around this problem is to obtain the UIView object for all my barButtons in viewWillAppear with:

我发现解决此问题的唯一方法是使用以下命令为 viewWillAppear 中的所有 barButton 获取 UIView 对象:

button1View = button1Item.value(forKey: "view") as? UIView

etc...

等等...

And then in my UITapGestureRecognizer action function I test:

然后在我的 UITapGestureRecognizer 动作函数中我测试:

if [button1View, button2View, button3View, button4View].contains(hitView)
{
  return
}

This is an ugly workaround! Any idea why (hitView is UIControl) should return false on a disabled bar button?

这是一个丑陋的解决方法!知道为什么(hitView 是 UIControl)应该在禁用的条形按钮上返回 false 吗?