识别点击导航栏标题

Ric*_*ard 39 uinavigationcontroller ios uitapgesturerecognizer swift

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

我想识别这个tap,然后动画tableHeaderView出现.可能会向下滑动TableView.

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

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

我正在使用Swift.

谢谢.

rob*_*off 56

UINavigationBar不公开其内部视图层次结构.没有受支持的方式来获取UILabel显示标题的引用.

您可以"手动"(通过搜索它subviews)查看其视图层次结构,但由于视图层次结构是私有的,因此可能会在未来的iOS版本中停止工作.

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

也就是说,设置非常简单:

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!")
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我几乎就在那里,但没有怀疑`userInteractionEnabled`.+1. (2认同)

Zia*_*Zia 24

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

  1. 添加UITapGestureRecognizertitleView.这似乎不优雅,需要您手动设置导航栏标题字体,所以我不推荐它.
  2. 添加UITapGestureRecognizernavigationBar.这看起来非常优雅,但采用这种方法的已发布答案的问题在于它们都会导致阻止导航栏中的控件工作.以下是我对此方法的实现,它允许您的控件继续工作.

斯威夫特3

// 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")

}
Run Code Online (Sandbox Code Playgroud)

  • 我不知道 `sender.location(in` 这是一个聪明的方法。我不能投票。 (2认同)

Ste*_*erg 23

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

  • 这是一个很好的解决方案,实际上,它非常完美且易于实现. (2认同)

meg*_*ezy 7

布鲁诺的答案对我来说是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")

}
Run Code Online (Sandbox Code Playgroud)


Bru*_*nha 5

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

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

func somethingWasTapped(_ sth: AnyObject){
    print("Hey there")
}
Run Code Online (Sandbox Code Playgroud)

  • 它将破坏导航栏中其他按钮的功能 (4认同)
  • 以我为例,这将另一个ViewController推入堆栈后破坏了后退按钮的功能。 (3认同)
  • 最好的方法来做到这一点。 (2认同)

Mah*_*t C 5

关于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")
}
Run Code Online (Sandbox Code Playgroud)