UINavigationBar Touch - PullRequest
       14

UINavigationBar Touch

21 голосов
/ 16 января 2010

Я хотел бы вызвать событие на ощупь, когда пользователь нажимает на заголовок панели навигации одного из моих просмотров.

Я немного растерялся из-за того, могу ли я получить доступ к представлению заголовка UINavigationBar, чтобы подключить к нему событие касания.

Возможно ли это вообще?

Ответы [ 9 ]

43 голосов
/ 08 мая 2012

Вы можете добавить распознаватель жестов одним нажатием на заголовок контроллера навигации. Я обнаружил, что в подвиде 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

Таким образом, вы можете использовать это для одного нажатия, или вы можете реализовать любой распознаватель жестов, который вы хотите для этого заголовка.

30 голосов
/ 30 января 2010

Решение, которое я нашел, - кнопка, я использую следующее (но я не знаю, насколько это «законно»):

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");
}

который записал «Заголовок крана» на консоли!

То, как я это сделал, может быть совершенно неверным, но может дать вам представление о том, на что вы можете обратить внимание. Это конечно помогло мне! Хотя, вероятно, есть лучший способ сделать это.

25 голосов
/ 12 июня 2012

Ни один из других ответов не помог мне. Вместо того, чтобы добавить жест к существующему подпредставлению навигационной панели или заменить 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];
}
9 голосов
/ 16 января 2010

Ссылка на класс UINavigationItem имеет свойство titleView, которое можно установить на свой пользовательский UIView.

Другими словами, создайте подкласс UIView с помощью сенсорных обработчиков, а затем, когда вы нажимаете на элемент навигации, присвойте свойству titleView этого элемента экземпляр вашего подкласса.

3 голосов
/ 29 сентября 2016

Это самое простое и простое решение в Swift, просто скопируйте / вставьте и заполните пробелы:

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

Обязательно установите userInteractionEnabled на true на titleView, по умолчанию он выключен.

1 голос
/ 19 января 2016

Это можно сделать, добавив 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")
  }
}
1 голос
/ 04 сентября 2014

Один из возможных вариантов: (используйте 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;
1 голос
/ 22 января 2014

Я не хотел указывать кнопку как пользовательскую 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!

0 голосов
/ 20 марта 2019

Опираясь на этот ответ и этот , я придерживался нижеследующего "функционального" подхода, я не уверен, что он более читабелен, но я предпочитаю его, вместо того, чтобы разбивать петля.

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