Подтвердить что ты не робот

Нажмите события в UINavigationBar, переопределенные распознающим жестом

Вопрос в первую очередь заключался в следующем:

Когда у вас есть tableView, как реализовать, что пользователь может нажать навигационную панель, чтобы прокрутить весь путь до вершины.

Решение:

- (void)viewDidLoad {
    UITapGestureRecognizer* tapRecon = [[UITapGestureRecognizer alloc]
              initWithTarget:self action:@selector(navigationBarDoubleTap:)];
    tapRecon.numberOfTapsRequired = 2;
    [navController.navigationBar addGestureRecognizer:tapRecon];
    [tapRecon release];
}

- (void)navigationBarDoubleTap:(UIGestureRecognizer*)recognizer {
    [tableView setContentOffset:CGPointMake(0,0) animated:YES];
}

Что работает как шарм!

Но Drarok указал на проблему:

Этот подход является только жизнеспособным, если у вас нет кнопки "Назад" или "rightBarButtonItem". Их события щелчка переопределяются распознавателем жестов

Мой вопрос:

Как я могу получить приятную функцию, которую мой NavigationBar можно щелкнуть, но все еще можно использовать кнопки "Назад" в моем приложении?

Итак, либо найдите другое решение, которое не отменяет кнопку "Назад" или не найдет решение, чтобы вернуть обратно кнопку назад:)

4b9b3361

Ответ 1

UIGestureRecognizerDelegate имеет метод под названием "gestureRecognizer: shouldReceiveTouch". Если вы можете указать, является ли сенсорный вид кнопкой, просто верните "НЕТ", в противном случае верните "ДА", и вы хорошо пойдете.

Ответ 2

Вместо определения местоположения я решил это, проверив класс UITouch.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return (![[[touch view] class] isSubclassOfClass:[UIControl class]]);
}

Обратите внимание, что кнопки навигации имеют тип UINavigationButton, который не отображается, поэтому проверка подкласса.

Этот метод относится к классу, который вы назначаете как делегат распознавателя жестов. Если вы только начинаете с распознавателей жестов, обратите внимание, что делегат устанавливается отдельно от цели.

Ответ 3

UIGestureRecognizer также имеет атрибут @property(nonatomic) BOOL cancelsTouchesInView. Из документации: A Boolean value affecting whether touches are delivered to a view when a gesture is recognized.

Итак, если вы просто делаете

tapRecon.cancelsTouchesInView = NO;

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

При нажатии кнопки на панели навигации, однако, ее действие выполняется (по желанию), но также выполняется действие UIGestureRecognizer. Если это вас не беспокоит, тогда это было бы самым простым решением, о котором я мог подумать.

Ответ 4

Версия iOS7:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    CGPoint point = [touch locationInView:touch.view];
    UINavigationBar *naviagationBar = (UINavigationBar *)touch.view;
    NSString *navigationItemViewClass = [NSString stringWithFormat:@"UINavigationItem%@%@",@"Button",@"View"];
    for (id subview in naviagationBar.subviews) {

        if (([subview isKindOfClass:[UIControl class]] ||
             [subview isKindOfClass:NSClassFromString(navigationItemViewClass)]) &&
             [subview pointInside:point withEvent:nil]) {

            return NO;
        }
    }
    return YES;
}

EDIT:

Состязание по углу кнопки "Назад" по-прежнему перезаписывается, поэтому вы создали этот код pointInside:withEvent:

CGRectContainsPoint((CGRect){ .origin = subview.frame.origin, .size = CGSizeMake(subview.frame.size.width + 16, subview.frame.size.height)}, point)

Ответ 5

Xamarin.iOS не предоставляет оболочки С# для классов Objective-C в частном API, поэтому чистая проверка подклассов, предложенная @ben-flynn выше, не будет работать здесь.

Несколько хакерских обходных пути заключается в проверке поля Description видов:

navigationTitleTap = new UITapGestureRecognizer (tap => DidTapNavigationTitle());

navigationTitleTap.ShouldReceiveTouch = (recognizer, touch) => 
    touch.View.Subviews.Any(sv => 
        // Is this the NavigationBar title or prompt?
        (sv.Description.StartsWith("<UINavigationItemView") || sv.Description.StartsWith("<UINavBarPrompt")) &&
        // Was the nested label actually tapped?
        sv.Subviews.OfType<UILabel>().Any(label =>
            label.Frame.Contains(touch.LocationInView(sv))));

NavigationController.NavigationBar.AddGestureRecognizer (navigationTitleTap);

Фильтр коллекции Linq .OfType<T> удобен, хотя при поиске определенных типов в иерархии представлений.

Ответ 6

Это сработало для меня, оно основано на ответе Ставаша. Я использую свойство view распознавателя жестов для возврата YES/NO в методе делегата.

Это старое приложение, поэтому очевидно, что это не ARC, не использует новые макеты или строки NSAttributed. Я оставляю это вам: p

- (void)viewDidLoad
{
    ...
    CGRect r = self.navigationController.navigationBar.bounds;
    UILabel *titleView = [[UILabel alloc] initWithFrame:r];
    titleView.autoresizingMask = 
      UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    titleView.textAlignment = NSTextAlignmentCenter;
    titleView.font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
    titleView.text = self.title;
    titleView.userInteractionEnabled = YES;
    UITapGestureRecognizer *tgr =
      [[UITapGestureRecognizer alloc] initWithTarget:self
                                              action:@selector(titleViewWasTapped:)];
    tgr.numberOfTapsRequired = 1;
    tgr.numberOfTouchesRequired = 1;
    tgr.delegate = self;
    [titleView addGestureRecognizer:tgr];
    [tgr release];
    self.navigationItem.titleView = titleView;
    [titleView release];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch
{
    // This method is needed because the navigation bar with back
    // buttons will swallow touch events
    return (gestureRecognizer.view == self.navigationItem.titleView);
}

Затем вы используете распознаватель жестов как обычно

- (void)titleViewWasTapped:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state != UIGestureRecognizerStateRecognized) {
        return;
    }
    ...
}